Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Refactor]: following elixir conventions #57

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions artifact/opt_versions/README.md
Original file line number Diff line number Diff line change
@@ -9,12 +9,15 @@ Honey Potion currently implements three optimizations:
Currently, it is not possible to enable or disable these optimizations via command line: they are hard-coded in the compiler, in the [optimizer.ex](../../lib/honey/optimizer.ex) module, e.g.:

```elixir
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}
defmodule Honey.Optimization.Optimizer do
alias Honey.{ConstantPropagation, DeadCodeElimination, TypePropagation}
alias Honey.Analysis.SemanticAnalysis

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
|> DCE.run()
|> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
end
end
@@ -25,14 +28,17 @@ This folder contains different implementations of the optimizer, with some of th
As an example, [this](constProp_TypeProp) file disables dead-code elimination and prints out the size of the abstract syntax tree of Honey Potion's intermediate program representation:

```elixir
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}
defmodule Honey.Optimization.Optimizer do
alias Honey.{ConstantPropagation, DeadCodeElimination, TypePropagation}
alias Honey.Analysis.SemanticAnalysis

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
# |> DCE.run()
# |> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
|> AstSize.output(env, " - Final")
|> Honey.Analysis.AstSize.output(env, " - Final")
end
end
```
15 changes: 9 additions & 6 deletions artifact/opt_versions/constProp_DeadCodeElim_TypeProp
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}

defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
|> DCE.run()
|> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
|> AstSize.output(env, " - Final")
|> Honey.Analysis.AstSize.output(env, " - Final")
# |> IO.inspect()
end
end
16 changes: 9 additions & 7 deletions artifact/opt_versions/constProp_TypeProp
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}

defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
# |> DCE.run()
# |> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
|> AstSize.output(env, " - Final")
|> Honey.Analysis.AstSize.output(env, " - Final")
#|> IO.inspect()
end
end
16 changes: 9 additions & 7 deletions artifact/opt_versions/noOptimization
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}

defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
# |> ConstantPropagation.run()
# |> DCE.run()
# |> DeadCodeElimination.run()
# |> TypePropagation.run(arguments, env)
|> AstSize.output(env, " - Final")
|> Honey.Analysis.AstSize.output(env, " - Final")
# |> IO.inspect()
end
end
16 changes: 9 additions & 7 deletions artifact/opt_versions/optimizer.ex
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}

defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
|> DCE.run()
|> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
# |> AstSize.output(env, " - Final")
# |> Honey.Analysis.AstSize.output(env, " - Final")
# |> IO.inspect()
end
end
16 changes: 9 additions & 7 deletions artifact/opt_versions/typeProp
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
defmodule Honey.Optimizer do
alias Honey.{ConstantPropagation, DCE, Analyze, TypePropagation}

defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""

def run(fun_def, arguments, env) do
fun_def |> Analyze.run()
fun_def
|> SemanticAnalysis.run()
# |> ConstantPropagation.run()
# |> DCE.run()
# |> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)
|> AstSize.output(env, " - Final")
|> Honey.Analysis.AstSize.output(env, " - Final")
# |> IO.inspect()
end
end
4 changes: 2 additions & 2 deletions docs/Language.md
Original file line number Diff line number Diff line change
@@ -33,12 +33,12 @@ Where attributes with a @ are optional and can be disabled. The map is represent
#### Functions used for maps.
Maps support functions to read and write data into it. The two main functions given to the user (that are also BPF-Helper functions) are:

`Honey.Bpf_helpers.bpf_map_lookup_elem` and `Honey.Bpf_helpers.bpf_map_update_elem`. The first one looks for a key in a map and the second one updates a key with a new value within a map.
`Honey.BpfHelpers.bpf_map_lookup_elem` and `Honey.BpfHelpers.bpf_map_update_elem`. The first one looks for a key in a map and the second one updates a key with a new value within a map.

Both of them take in the map name as an atom and the key as the first two arguments and `bpf_map_update_elem` takes the new value as the third argument.

## BPF-Helper Functions
Honey gives the user direct access to some of the functions in the BPF-Helper library. The most notable one is `Honey.Bpf_helpers.bpf_printk`, which allows you to print a C-formatted string to `/sys/kernel/debug/tracing/trace_pipe`. To read the output, just cat that directory and it will update live. The other two have been described in the above section.
Honey gives the user direct access to some of the functions in the BPF-Helper library. The most notable one is `Honey.BpfHelpers.bpf_printk`, which allows you to print a C-formatted string to `/sys/kernel/debug/tracing/trace_pipe`. To read the output, just cat that directory and it will update live. The other two have been described in the above section.

## Recursive Functions
It is possible to define recursive functions and call them from `main/1`. For example, let's define a function that recursively sums two natural numbers:
4 changes: 2 additions & 2 deletions docs/Makefile.md
Original file line number Diff line number Diff line change
@@ -6,12 +6,12 @@ The generic Makefile we use to compile our examples is located in /priv/BPF_Boil
## Dependency Directories
All of the directories used in the Makefile are relative to the Examples folder. (Notice how there is a Makefile there).

When a user creates a directory and adds Honey-Potion as a dependency these directories aren't valid anymore. To fix this the Honey.Compiler module addresses this by defining some of these directories at runtime, making it work without depending on how the user decided to include Honey-Potion as a dependency.
When a user creates a directory and adds Honey-Potion as a dependency these directories aren't valid anymore. To fix this the Honey.Compiler.Pipeline module addresses this by defining some of these directories at runtime, making it work without depending on how the user decided to include Honey-Potion as a dependency.

## Order of Operations
To compile our eBPF programs, we take some steps. From now on I'll describe each of them in order and give general explanation on what it does/generates.

When reading the Makefile code keep in mind that we create in the user directory (SRC_DIR) 3 folders, /src, /obj and /bin, of which /src already has the files to be compiled when we get to Honey.Compiler.
When reading the Makefile code keep in mind that we create in the user directory (SRC_DIR) 3 folders, /src, /obj and /bin, of which /src already has the files to be compiled when we get to Honey.Compiler.Pipeline.

### Object Files

2 changes: 1 addition & 1 deletion examples/lib/Case.ex
Original file line number Diff line number Diff line change
@@ -18,6 +18,6 @@ defmodule Case do
_ -> x + 1
end

Honey.Bpf_helpers.bpf_printk(["Result: %d", return])
Honey.BpfHelpers.bpf_printk(["Result: %d", return])
end
end
8 changes: 4 additions & 4 deletions examples/lib/Cond.ex
Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@ defmodule Cond do
def main(_) do
x = 32
cond do
x == 23 -> Honey.Bpf_helpers.bpf_printk(["Is 23."])
x == 23445 -> Honey.Bpf_helpers.bpf_printk(["Is 23445."])
x == 51234 -> Honey.Bpf_helpers.bpf_printk(["Is 51234."])
x== 32 -> Honey.Bpf_helpers.bpf_printk(["Is 32."])
x == 23 -> Honey.BpfHelpers.bpf_printk(["Is 23."])
x == 23445 -> Honey.BpfHelpers.bpf_printk(["Is 23445."])
x == 51234 -> Honey.BpfHelpers.bpf_printk(["Is 51234."])
x== 32 -> Honey.BpfHelpers.bpf_printk(["Is 32."])
end
0
end
10 changes: 4 additions & 6 deletions examples/lib/CountSysCalls.ex
Original file line number Diff line number Diff line change
@@ -5,16 +5,14 @@ defmodule CountSysCalls do
{"SysCall: enter_kill (62) | Qtt:", 62}, {"SysCall: enter_mkdir (83) | Qtt:", 83},
{"SysCall: enter_getrandom (318) | Qtt:", 318}] # Defines the {"Name", key} of each printed element

defmap( # Defines a map with BPF_MAP_TYPE_ARRAY type, 335 entries and the above printlist
:Count_Sys_Calls_Invoked,
%{type: BPF_MAP_TYPE_ARRAY, max_entries: 335, print: true, print_elem: printlist}
)
# Defines a map with BPF_MAP_TYPE_ARRAY type, 335 entries and the above printlist
defmap(:Count_Sys_Calls_Invoked, :bpf_array, [max_entries: 335, print: true, print_elem: printlist])

@sec "tracepoint/raw_syscalls/sys_enter" # Sets our trigger to sys_enter
def main(ctx) do
id = ctx.id # Grabs the ID of the sys_enter, which represents what sys_enter call was done

id_count = Honey.Bpf_helpers.bpf_map_lookup_elem(:Count_Sys_Calls_Invoked, id) # Grabs the old value in the map
Honey.Bpf_helpers.bpf_map_update_elem(:Count_Sys_Calls_Invoked, id, id_count + 1) # and increments it by one
id_count = Honey.BpfHelpers.bpf_map_lookup_elem(:Count_Sys_Calls_Invoked, id) # Grabs the old value in the map
Honey.BpfHelpers.bpf_map_update_elem(:Count_Sys_Calls_Invoked, id, id_count + 1) # and increments it by one
end
end
2 changes: 1 addition & 1 deletion examples/lib/CtxAccess.ex
Original file line number Diff line number Diff line change
@@ -7,6 +7,6 @@ defmodule CtxAccess do
#Shows how to access ctx arguments (Make sure to name the argument ctx!).

targetid = ctx.pid
Honey.Bpf_helpers.bpf_printk(["PID of callee: %d; PID of target: %d;", Honey.Bpf_helpers.bpf_get_current_pid_tgid(), targetid])
Honey.BpfHelpers.bpf_printk(["PID of callee: %d; PID of target: %d;", Honey.BpfHelpers.bpf_get_current_pid_tgid(), targetid])
end
end
6 changes: 3 additions & 3 deletions examples/lib/DCE.ex
Original file line number Diff line number Diff line change
@@ -4,11 +4,11 @@ defmodule DCE do
@sec "tracepoint/syscalls/sys_enter_kill"
def main(_ctx) do
if true do
1 # This one also doesn't show up in DCE, as this if has no return that is kept.
1 # This one also doesn't show up in DeadCodeElimination, as this if has no return that is kept.
# Taking out the 0 below makes it be stored.
else
Honey.Bpf_helpers.bpf_printk(["This will never print!"])
Honey.Bpf_helpers.bpf_printk(["This will also not be in the AST after DCE!"])
Honey.BpfHelpers.bpf_printk(["This will never print!"])
Honey.BpfHelpers.bpf_printk(["This will also not be in the AST after DCE!"])
end
0
end
2 changes: 1 addition & 1 deletion examples/lib/Fact.ex
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ defmodule Honey_Fact do
a = fuel 3, fact(const)
b = fuel 2, fact(id)
c = a + b
Honey.Bpf_helpers.bpf_printk(["%d", c])
Honey.BpfHelpers.bpf_printk(["%d", c])
end
end

8 changes: 3 additions & 5 deletions examples/lib/Forcekill.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
defmodule Forcekill do
use Honey, license: "Dual BSD/GPL"

defmap( # Defines an eBPF map of the BPF_MAP_TYPE_HASH with 64 entries
:ForceKills,
%{type: BPF_MAP_TYPE_HASH, max_entries: 64, print: true}
)
# Defines an eBPF map of the BPF_MAP_TYPE_HASH with 64 entries
defmap(:ForceKills, :bpf_hash, [max_entries: 64, print: true])

@sec "tracepoint/syscalls/sys_enter_kill" # Sets our trigger to be sys_enter_kill
def main(ctx) do
@@ -15,7 +13,7 @@ defmodule Forcekill do

cond do
sig == target_sig -> # In case the kill had the sig of 9 or <target_sig> (kill -9 <PID>)
Honey.Bpf_helpers.bpf_map_update_elem(:ForceKills, pid, stored_value, :BPF_NOEXIST) # Stores a value into the <pid> key. It will be printed from now on.
Honey.BpfHelpers.bpf_map_update_elem(:ForceKills, pid, stored_value, :BPF_NOEXIST) # Stores a value into the <pid> key. It will be printed from now on.
end
0
end
2 changes: 1 addition & 1 deletion examples/lib/GetPID.ex
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@ defmodule GetPID do

#Shows how to use c-like arguments on string.

Honey.Bpf_helpers.bpf_printk(["Current PID: %d; Another number: 5", Honey.Bpf_helpers.bpf_get_current_pid_tgid(), x])
Honey.BpfHelpers.bpf_printk(["Current PID: %d; Another number: 5", Honey.BpfHelpers.bpf_get_current_pid_tgid(), x])
end
end
2 changes: 1 addition & 1 deletion examples/lib/HelloWorld.ex
Original file line number Diff line number Diff line change
@@ -9,6 +9,6 @@ defmodule HelloWorld do
# Shows how to print to /sys/kernel/debug/tracing/trace_pipe.
# Run "sudo cat /sys/kernel/debug/tracing/trace_pipe" to see the output!

Honey.Bpf_helpers.bpf_printk(["Hello World", nil_var])
Honey.BpfHelpers.bpf_printk(["Hello World", nil_var])
end
end
4 changes: 2 additions & 2 deletions examples/lib/IfThenElse.ex
Original file line number Diff line number Diff line change
@@ -7,9 +7,9 @@ defmodule If_Then_Else do
# Shows that if and else are possible.

if (true) do
Honey.Bpf_helpers.bpf_printk(["True"])
Honey.BpfHelpers.bpf_printk(["True"])
else
Honey.Bpf_helpers.bpf_printk(["False"])
Honey.BpfHelpers.bpf_printk(["False"])
end
0
end
2 changes: 1 addition & 1 deletion examples/lib/IntegerStringPatternMatching.ex
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ defmodule Integer_String_Pattern_Matching do
str = "foo"
1 = x
"foo" = str
Honey.Bpf_helpers.bpf_printk(["Success"])
Honey.BpfHelpers.bpf_printk(["Success"])

# The following line raises an error:
"bar" = str
2 changes: 1 addition & 1 deletion examples/lib/List.ex
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@ defmodule Honey_List do
[_, any_tuple] = [three, one_two]
{x, _} = any_tuple
# X must be equals 1
Honey.Bpf_helpers.bpf_printk(["x: %d", x])
Honey.BpfHelpers.bpf_printk(["x: %d", x])
end
end
8 changes: 4 additions & 4 deletions examples/lib/ListSysCalls.ex
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@ defmodule ListSysCalls do
id = ctx.id
enter_kill = 62; enter_mkdir = 83; enter_getrandom = 318;
cond do
id == enter_kill -> Honey.Bpf_helpers.bpf_printk(["Syscall of type enter_kill"])
id == enter_mkdir -> Honey.Bpf_helpers.bpf_printk(["Syscall of type enter_mkdir"])
id == enter_getrandom -> Honey.Bpf_helpers.bpf_printk(["Syscall of type enter_getrandom"])
id == enter_kill -> Honey.BpfHelpers.bpf_printk(["Syscall of type enter_kill"])
id == enter_mkdir -> Honey.BpfHelpers.bpf_printk(["Syscall of type enter_mkdir"])
id == enter_getrandom -> Honey.BpfHelpers.bpf_printk(["Syscall of type enter_getrandom"])
# true -> #These ignored types are recursive as they are created from the process and lead to another call of itself.
# if !(id == 0) and !(id == 1) and !(id == 7) and !(id == 47) do
# Honey.Bpf_helpers.bpf_printk(["Syscall of type %d", id])
# Honey.BpfHelpers.bpf_printk(["Syscall of type %d", id])
# end
end
0
47 changes: 20 additions & 27 deletions examples/lib/Maps.ex
Original file line number Diff line number Diff line change
@@ -16,40 +16,33 @@ defmodule Honey_Maps do
# If print_elem is not set, Honey will attempt to print as much as possible of the map.
# See Forcekill for an example.

defmap(:Example_map, :bpf_array, [max_entries: 7, print: true])

defmap(
:Example_map,
%{type: BPF_MAP_TYPE_ARRAY, max_entries: 7, print: true}
)

defmap(
:Second_Example_map,
%{type: BPF_MAP_TYPE_ARRAY, max_entries: 5, print: false, print_elem: printlist}
)
defmap(:Second_Example_map, :bpf_array, [max_entries: 5, print: false, print_elem: printlist])

@sec "tracepoint/syscalls/sys_enter_write"
def main(_ctx) do
# To get elements from the map, use bpf_map_lookup_elem from Bpf_helpers!
entry_0 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 0)
entry_1 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 1)
entry_2 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 2)
entry_3 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 3)
entry_4 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 4)
entry_5 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 5)
entry_6 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 6)
entry_7 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Second_Example_map, 0)
#entry_8 = Honey.Bpf_helpers.bpf_map_lookup_elem(:Example_map, 8) # TODO: delete this line
entry_0 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 0)
entry_1 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 1)
entry_2 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 2)
entry_3 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 3)
entry_4 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 4)
entry_5 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 5)
entry_6 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 6)
entry_7 = Honey.BpfHelpers.bpf_map_lookup_elem(:Second_Example_map, 0)
#entry_8 = Honey.BpfHelpers.bpf_map_lookup_elem(:Example_map, 8) # TODO: delete this line

# To update elements from the map, use bpf_map_update_elem from Bpf_helpers!
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 0, entry_0 + 1)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 1, entry_1 + 2)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 2, entry_2 + 3)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 3, entry_3 + 4)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 4, entry_4 + 5)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 5, entry_5 + 6)
Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 6, entry_6 + 7)
Honey.Bpf_helpers.bpf_map_update_elem(:Second_Example_map, 0, entry_7 + 8)
#Honey.Bpf_helpers.bpf_map_update_elem(:Example_map, 8, entry_8 + 9) # TODO: delete this line
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 0, entry_0 + 1)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 1, entry_1 + 2)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 2, entry_2 + 3)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 3, entry_3 + 4)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 4, entry_4 + 5)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 5, entry_5 + 6)
Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 6, entry_6 + 7)
Honey.BpfHelpers.bpf_map_update_elem(:Second_Example_map, 0, entry_7 + 8)
#Honey.BpfHelpers.bpf_map_update_elem(:Example_map, 8, entry_8 + 9) # TODO: delete this line

0
end
10 changes: 4 additions & 6 deletions examples/lib/TrafficCount.ex
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
defmodule TrafficCount do
use Honey, license: "Dual BSD/GPL"

defmap( # Defines an eBPF map of the BPF_MAP_TYPE_HASH with 64 entries
:TrafficCount,
%{type: BPF_MAP_TYPE_HASH, max_entries: 64, print: true, key_size: :char6}
)
# Defines an eBPF map of the BPF_MAP_TYPE_HASH with 64 entries
defmap(:TrafficCount, :bpf_hash, [max_entries: 64, print: true, key_size: :char6])

@sec "xdp_md"
def main(_ctx) do
Honey.Ethhdr.init() #Should only be called once!
src = Honey.Ethhdr.h_source() #Returns a void* to h_source. Maybe should have unique representation?

count = Honey.Bpf_helpers.bpf_map_lookup_elem(:TrafficCount, src, 0)
count = Honey.BpfHelpers.bpf_map_lookup_elem(:TrafficCount, src, 0)
count = count + 1

Honey.Bpf_helpers.bpf_map_update_elem(:TrafficCount, src, count)
Honey.BpfHelpers.bpf_map_update_elem(:TrafficCount, src, count)

Honey.XDP.pass()
end
2 changes: 1 addition & 1 deletion examples/lib/Tuple.ex
Original file line number Diff line number Diff line change
@@ -5,6 +5,6 @@ defmodule Honey_Tuple do
def main(_) do
y = 2
{1, {2, {"some string", x}}} = {1, {y, {"some string", 4}}}
Honey.Bpf_helpers.bpf_printk(["x: %d", x])
Honey.BpfHelpers.bpf_printk(["x: %d", x])
end
end
2 changes: 1 addition & 1 deletion examples/lib/linked_list.ex
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ defmodule Honey_List_Linked do

[_three | a] = t
[two | _a] = a
Honey.Bpf_helpers.bpf_printk(["%d", two])
Honey.BpfHelpers.bpf_printk(["%d", two])
0
end
end
72 changes: 46 additions & 26 deletions lib/honey.ex
Original file line number Diff line number Diff line change
@@ -9,22 +9,28 @@ defmodule Honey do
## Aliases
- `Mix.Task.Compiler`: Manages compilation tasks.
- `Honey.Guard`: Stops execution if main doesn't exist.
- `Honey.Fuel`: Unrolls function calls.
- `Honey.Optimizer`: Optimizes the AST with DCE (Dead Code Elimination) and CP (Constant Propagation) and performs variable analysis.
- `Honey.Info`: Gathers information about the AST.
- `Honey.Generator`: Uses the gathered info to generate frontend and backend code.
- `Honey.Write`: Writes files into the appropriate folders for compilation.
- `Honey.Compiler`: Compiles the files into `userdir/bin/`.
- `Honey.Utils.Guard`: Stops execution if main doesn't exist.
- `Honey.AST.RecursionExpansion`: Unrolls function calls.
- `Honey.Optimization.Optimizer`: Optimizes the AST with DCE (Dead Code Elimination) and CP (Constant Propagation) and performs variable analysis.
- `Honey.Runtime.Info`: Gathers information about the AST.
- `Honey.Compiler.CodeGenerator`: Uses the gathered info to generate frontend and backend code.
- `Honey.Utils.Write`: Writes files into the appropriate folders for compilation.
- `Honey.Compiler.Pipeline`: Compiles the files into `userdir/bin/`.
"""
alias Mix.Task.Compiler
alias Honey.Guard
alias Honey.Fuel
alias Honey.Optimizer
alias Honey.Info
alias Honey.Generator
alias Honey.Write
alias Honey.Compiler
alias Honey.Utils.Guard
alias Honey.AST.RecursionExpansion
alias Honey.Optimization.Optimizer
alias Honey.Runtime.Info
alias Honey.Compiler.CodeGenerator
alias Honey.Utils.Write
alias Honey.Compiler.Pipeline

@ebpf_types %{
bpf_array: BPF_MAP_TYPE_ARRAY,
bpf_hash: BPF_MAP_TYPE_HASH,
bpf_percpu_array: BPF_MAP_TYPE_PERCPU_ARRAY,
bpf_percpu_hash: BPF_MAP_TYPE_PERCPU_HASH
}

@doc """
Honey-Potion runs using the __before_compile__ macro. So here is where we keep the Honey-Potion pipeline.
@@ -34,13 +40,13 @@ defmodule Honey do

{arguments, func_ast} = Info.get_ast(main_def)

final_ast = func_ast |> Fuel.burn_fuel(env) |> Optimizer.run(arguments, env)
final_ast = func_ast |> RecursionExpansion.burn_fuel(env) |> Optimizer.run(arguments, env)

{backend_code, frontend_code} = Generator.generate_code(env, final_ast)
{backend_code, frontend_code} = CodeGenerator.generate_code(env, final_ast)

Write.write_ouput_files(backend_code, frontend_code, env)

Compiler.compile_bpf(env)
Pipeline.compile_bpf(env)

Module.delete_definition(env.module, {_target_func = :main, _target_arity = 1})

@@ -56,23 +62,37 @@ defmodule Honey do
Users can define maps using the macro defmap. For example, to create a map named my_map, you can:
```
defmap(:my_map,
%{type: BPF_MAP_TYPE_ARRAY,
max_entries: 10}
)
defmap(:my_map, :bpf_array, max_entries: 10)
```
In the current version, the types of maps available are:
In the current version, the ebpf types of maps available are:
- BPF_MAP_TYPE_ARRAY: You only need to specify the maximum number of entries (max_entries) and the map is ready to use.
- BPF_MAP_TYPE_HASH: The key is an integer, and you only need to provide the maximum number of entries (max_entries) and the map is ready to use,
- BPF_MAP_TYPE_PERCPU_ARRAY: Same as BPF_MAP_TYPE_ARRAY.
- BPF_MAP_TYPE_PERCPU_HASH: Same as BPF_MAP_TYPE_HASH.
And they are represented by the following atoms
- :bpf_array
- :bpf_hash
- :bpf_percpu_array
- :bpf_percpu_hash
"""
defmacro defmap(ebpf_map_name, ebpf_map) do
defmacro defmap(ebpf_map_name, ebpf_map_type, opts \\ []) do
ebpf_types = @ebpf_types

quote do
ebpf_map_name = unquote(ebpf_map_name)
ebpf_map_content = unquote(ebpf_map)
ebpf_map_type_atom = unquote(ebpf_map_type)

ebpf_map_type =
Map.fetch!(
unquote(Macro.escape(ebpf_types)),
ebpf_map_type_atom
)

ebpf_map_content = %{type: ebpf_map_type, options: unquote(opts)}
@ebpf_maps %{name: ebpf_map_name, content: ebpf_map_content}
end
end
@@ -92,7 +112,7 @@ defmodule Honey do
Module.register_attribute(__CALLER__.module, :ebpf_maps, accumulate: true)

quote do
import Honey.Fuel
import Honey.AST.RecursionExpansion
import Honey
@before_compile unquote(__MODULE__)
@on_definition unquote(__MODULE__)
6 changes: 3 additions & 3 deletions lib/honey/ast_size.ex → lib/honey/analysis/ast_size.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
defmodule AstSize do
defmodule Honey.Analysis.AstSize do
@moduledoc """
This module measures the size of the Elixir AST.
"""
alias Honey.Utils
alias Honey.Utils.Core

@doc """
Outputs the size of the AST.
Usage: output(AST, environment, optional<suffix_to_size>)
"""
def output(ast, env, step \\ "") do
{_, size} = Macro.postwalk(ast, 0, fn seg, acc -> {seg, 1 + acc} end)
IO.puts(Utils.module_name(env) <> " - " <> Integer.to_string(size) <> step)
IO.puts(Core.module_name(env) <> " - " <> Integer.to_string(size) <> step)
ast
end
end
114 changes: 114 additions & 0 deletions lib/honey/analysis/elixir_types.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
defmodule Honey.Analysis.ElixirTypes do
@moduledoc """
This module represents a type in the Elixir AST.
More specifically this module keeps a struct that represents the details of a
type for when it gets translated to C.
"""

@derive {Inspect, optional: [:name, :struct, :function, :fields]}
defstruct name: nil, struct: nil, function: nil, fields: nil

def new(name) when is_atom(name) do
%__MODULE__{name: name}
end

def new(name, fields) when is_atom(name) and is_list(fields) do
%__MODULE__{name: name, fields: fields}
end

def merge_types(_type_list) do
# TODO
end

def type_any() do
new(:any)
end

def type_float() do
new(:float)
end

def type_integer() do
new(:integer)
end

def type_boolean() do
new(:boolean)
end

def type_atom() do
new(:atom)
end

def type_bitstring() do
new(:string)
end

def type_binary() do
new(:binary)
end

def type_void() do
new(:void)
end

def type_struct(name) do
%__MODULE__{name: name, struct: Honey.ElixirStructType.new()}
end

def type_function() do
new(:function)
end

def type_list() do
new(:list)
end

def type_tuple() do
new(:tuple)
end

def type_invalid() do
new(:invalid)
end

# The following types were hardcoded. That was a shortcut to present a proof of concept.
# A better structure to modularize it is needed.

def type_ctx() do
new(:type_ctx)
end
end

defmodule Honey.ElixirFunctionType do
defstruct [:arguments, :return_type]

def new() do
end
end

defmodule Honey.ElixirFunctionArgument do
defstruct [:name, :type, :optional]

def new(name, type, optional \\ false) do
%Honey.ElixirFunctionArgument{name: name, type: type, optional: optional}
end
end

defmodule Honey.ElixirStructField do
defstruct name: "", type: nil

def new(_name, _type) do
end
end

defmodule Honey.ElixirStructType do
defstruct fields: []

def new() do
%Honey.ElixirStructType{}
end

def add_field(_field = %Honey.ElixirStructField{}) do
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Honey.Analyze do
defmodule Honey.Analysis.SemanticAnalysis do
@moduledoc """
Runs analysis on the elixir AST. Currently does liveness, last use, scope and reusable variables analysis.
All AST elements will now have uv, sv and dv which are all branch aware.
@@ -7,7 +7,7 @@ defmodule Honey.Analyze do
- DV are for variables that aren't used anymore from that point onwards and are in scope.
This way DV are variables that are in scope and aren't being used, this way it can be re-used freely.
"""
import Honey.Utils, only: [is_var: 1, var_to_key: 1]
import Honey.Utils.Core, only: [is_var: 1, var_to_key: 1]

@doc """
Runs the analysis given an elixir AST.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Honey.Fuel do
defmodule Honey.AST.RecursionExpansion do
@moduledoc """
Manages Fuel for function calls.
In Honey-Potion, Fuel is the ammount of recursive calls that a function call can generate.
@@ -13,7 +13,7 @@ defmodule Honey.Fuel do
- Must be in the same module as main/1
- It doesn't expand mutual recursions yet
"""
import Honey.Utils, only: [is_var: 1, is_call: 1, compile_error!: 2]
import Honey.Utils.Core, only: [is_var: 1, is_call: 1, compile_error!: 2]

@doc """
Defines the macro fuel which adds the fuel ammount into the metadata of a function call.
27 changes: 0 additions & 27 deletions lib/honey/c_libraries/bpf.ex

This file was deleted.

11 changes: 0 additions & 11 deletions lib/honey/c_libraries/xdp.ex

This file was deleted.

24 changes: 12 additions & 12 deletions lib/honey/boilerplates.ex → lib/honey/codegen/boilerplates.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
defmodule Honey.Boilerplates do
defmodule Honey.Codegen.Boilerplates do
@moduledoc """
Module for generating C boilerplate needed to translate Elixir to eBPF readable C.
Also picks up the translated code and puts it in the appropriate section.
"""
alias Honey.Boilerplates
alias Honey.Codegen.Boilerplates

alias Honey.ElixirType
alias Honey.Info
alias Honey.Analysis.ElixirTypes
alias Honey.Runtime.Info
alias Honey.TypeSet
alias Honey.Utils
alias Honey.Utils.Core

import Honey.Utils, only: [gen: 1]
import Honey.Utils.Core, only: [gen: 1]

defstruct [:libbpf_prog_type, :func_args, :license, :elixir_maps, :requires, :translated_code]

@@ -43,7 +43,7 @@ defmodule Honey.Boilerplates do
Generates the generic front-end for the bpf program.
"""
def generate_frontend_code(env) do
module_name = Utils.module_name(env)
module_name = Core.module_name(env)
{_, sec,_,_} = Info.get_backend_info(env)

include = """
@@ -155,7 +155,7 @@ defmodule Honey.Boilerplates do
only what has been requested. This is toggled by adding or removing the -p argument when calling the binary.
"""
def generate_output_chooser(env) do
module_name = Utils.module_name(env)
module_name = Core.module_name(env)
output = """
void output(struct #{module_name}_bpf* skel, uint time, bool all){
if(time == 0){
@@ -193,7 +193,7 @@ defmodule Honey.Boilerplates do
output = generate_output_func(env)
output_always = generate_output_func(env, true)

module_name = Utils.module_name(env)
module_name = Core.module_name(env)

decl = "void output_opt(struct #{module_name}_bpf* skel);\n"
decl_always = "void output_all(struct #{module_name}_bpf* skel);\n"
@@ -286,7 +286,7 @@ defmodule Honey.Boilerplates do
end
end) |> Enum.join

module_name = Utils.module_name(env)
module_name = Core.module_name(env)

if(printAll == false) do
if(output == "") do
@@ -551,7 +551,7 @@ defmodule Honey.Boilerplates do
Returns the boilerplate ending of the main function of the backend.
"""
def generate_ending_main_code(return_var_name, return_var_type) do
int_type = TypeSet.new(ElixirType.type_integer())
int_type = TypeSet.new(ElixirTypes.type_integer())
return_text = cond do
return_var_type == int_type -> (
# Inspect debug
@@ -561,7 +561,7 @@ defmodule Honey.Boilerplates do
""")
)

TypeSet.has_type(return_var_type, ElixirType.type_integer()) -> (
TypeSet.has_type(return_var_type, ElixirTypes.type_integer()) -> (
# Inspect debug
IO.inspect("We can return a non-integer!; Caution.")
gen("""
34 changes: 34 additions & 0 deletions lib/honey/codegen/c_libraries/bpf.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule Honey.BpfHelpers do
@moduledoc """
This module provides helper functions for interacting with eBPF maps and system calls.
The functions in this module act as placeholders for BPF helper functions that are commonly
used in eBPF programs. Each function returns a value of type `integer`, which is the typical
return type of eBPF helper functions.
## Functions
* `bpf_printk/1` - Simulates a call to `bpf_printk`, used for debugging in eBPF programs.
* `bpf_get_current_pid_tgid/0` - Retrieves the current process ID (PID) and thread group ID (TGID).
* `bpf_map_lookup_elem/2` - Simulates looking up an element in an eBPF map.
* `bpf_map_lookup_elem/3` - Simulates looking up an element in an eBPF map, with a default value.
* `bpf_map_update_elem/3` - Simulates updating an element in an eBPF map.
* `bpf_map_update_elem/4` - Simulates updating an element in an eBPF map with flags.
These functions serve as stubs that will be replaced with actual eBPF calls or compiled into
lower-level BPF instructions.
"""
import Honey.Analysis.ElixirTypes, only: [type_integer: 0]

def bpf_printk(_str), do: type_integer()

def bpf_get_current_pid_tgid(), do: type_integer()

def bpf_map_lookup_elem(_map, _key), do: type_integer()

def bpf_map_lookup_elem(_map, _key, _default_value), do: type_integer()

def bpf_map_update_elem(_map, _key, _value, _flags), do: type_integer()

def bpf_map_update_elem(_map, _key, _value), do: type_integer()
end
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
defmodule Honey.Ethhdr do
alias Honey.ElixirType
alias Honey.Analysis.ElixirTypes

def init() do
ElixirType.type_invalid()
ElixirTypes.type_invalid()
end

def const_udp() do
ElixirType.type_integer()
ElixirTypes.type_integer()
end

def ip_protocol() do
ElixirType.type_integer()
ElixirTypes.type_integer()
end

def destination_port() do
ElixirType.type_integer()
ElixirTypes.type_integer()
end

def set_destination_port(_dest_port) do
ElixirType.type_integer()
ElixirTypes.type_integer()
end

def h_source() do
ElixirType.type_void()
ElixirTypes.type_void()
end
end
File renamed without changes.
11 changes: 11 additions & 0 deletions lib/honey/codegen/c_libraries/xdp.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Honey.XDP do
alias Honey.Analysis.ElixirTypes

def drop() do
ElixirTypes.type_integer()
end

def pass() do
ElixirTypes.type_integer()
end
end
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
defmodule Honey.Generator do
defmodule Honey.Compiler.CodeGenerator do
@moduledoc """
Groups the Boilerplates and Translation Modules to generate both the front-end and back-end code.
"""
alias Honey.Boilerplates
alias Honey.Info
alias Honey.Translator
alias Honey.Codegen.Boilerplates
alias Honey.Runtime.Info
alias Honey.Compiler.Translator

@doc """
Generates both the front-end code and the back-end code.
8 changes: 4 additions & 4 deletions lib/honey/compiler.ex → lib/honey/compiler/pipeline.ex
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
defmodule Honey.Compiler do
defmodule Honey.Compiler.Pipeline do
@moduledoc """
Contains functions used to compile the generated code.
"""
alias Honey.Directories
alias Honey.Utils
alias Honey.Utils.Directories
alias Honey.Utils.Core

@doc """
Compiles the files located in userdir/src using a pre-defined Makefile that was added in write module.
"""
def compile_bpf(env) do
mod_name = Utils.module_name(env)
mod_name = Core.module_name(env)

userdir = Directories.userdir(env)
libsdir = Directories.libsdir()
92 changes: 46 additions & 46 deletions lib/honey/translator.ex → lib/honey/compiler/translator.ex
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
defmodule Honey.TranslatorContext do
defmodule Honey.Compiler.TranslatorContext do
defstruct [:maps]

def new(maps) do
%__MODULE__{maps: maps}
end
end

defmodule Honey.Translator do
defmodule Honey.Compiler.Translator do
@moduledoc """
Translates the elixir AST into eBPF readable C code.
"""
alias Honey.Boilerplates
alias Honey.Guard
alias Honey.ElixirType
alias Honey.TranslatedCode
alias Honey.Codegen.Boilerplates
alias Honey.Utils.Guard
alias Honey.Analysis.ElixirTypes
alias Honey.Runtime.TranslatedCode
alias Honey.TypeSet

import Honey.Utils, only: [gen: 1, var_to_string: 1, is_var: 1]
import Honey.Utils.Core, only: [gen: 1, var_to_string: 1, is_var: 1]

@doc """
#Translates the main function.
@@ -25,7 +25,7 @@ defmodule Honey.Translator do
case func_name do
"main" ->
Guard.ensure_sec_type!(sec)
context = Honey.TranslatorContext.new(elixir_maps)
context = Honey.Compiler.TranslatorContext.new(elixir_maps)
translated_code = to_c(ast, context)

sec
@@ -139,7 +139,7 @@ defmodule Honey.Translator do
end

# C libraries
def to_c({{:., _, [Honey.Bpf_helpers, function]}, _, params}, context) do
def to_c({{:., _, [Honey.BpfHelpers, function]}, _, params}, context) do
case function do
:bpf_printk ->
[[string | other_params]] = params
@@ -176,7 +176,7 @@ defmodule Honey.Translator do
int #{result_var} = 0;
"""
|> gen()
|> TranslatedCode.new(result_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(result_var, TypeSet.new(ElixirTypes.type_integer()))

:bpf_map_lookup_elem ->
params =
@@ -226,7 +226,7 @@ defmodule Honey.Translator do

key_code =
cond do
TypeSet.has_unique_type(key.return_var_type, ElixirType.type_void()) ->
TypeSet.has_unique_type(key.return_var_type, ElixirTypes.type_void()) ->
"""
#{key.code}
Generic *#{result_var_pointer} = bpf_map_lookup_elem(&#{str_map_name}, #{key.return_var_name});
@@ -276,7 +276,7 @@ defmodule Honey.Translator do
""")
|> gen()
# |> TranslatedCode.new(tuple_translation.return_var_name)
|> TranslatedCode.new(item_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(item_var, TypeSet.new(ElixirTypes.type_integer()))

# Ideally this will return a tuple with two values: A boolean representing whether the value was found
# and the value itself (:nil if it wasn't found).
@@ -386,7 +386,7 @@ defmodule Honey.Translator do

update =
cond do
TypeSet.has_unique_type(key.return_var_type, ElixirType.type_void()) ->
TypeSet.has_unique_type(key.return_var_type, ElixirTypes.type_void()) ->
"""
#{generic_value.return_var_name}.value.integer = #{value.return_var_name};
int #{result_var_c} = bpf_map_update_elem(&#{str_map_name}, (#{key.return_var_name}), &#{generic_value.return_var_name}, #{flags_str});
@@ -410,7 +410,7 @@ defmodule Honey.Translator do

(start <> update)
|> gen()
|> TranslatedCode.new(result_var_c, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(result_var_c, TypeSet.new(ElixirTypes.type_integer()))

true ->
raise "bpf_map_update_elem: In this verison of Honey Potion, we cannot use this function with map type #{map_content.type}."
@@ -421,7 +421,7 @@ defmodule Honey.Translator do

"int #{result_var} = bpf_get_current_pid_tgid();\n"
|> gen()
|> TranslatedCode.new(result_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(result_var, TypeSet.new(ElixirTypes.type_integer()))
end
end

@@ -442,11 +442,11 @@ defmodule Honey.Translator do
return XDP_ABORTED;
"""
|> gen()
|> TranslatedCode.new("", TypeSet.new(ElixirType.type_invalid()))
|> TranslatedCode.new("", TypeSet.new(ElixirTypes.type_invalid()))

# We don't need code to initialize a constant.
:const_udp ->
"" |> TranslatedCode.new("IPPROTO_UDP", TypeSet.new(ElixirType.type_integer()))
"" |> TranslatedCode.new("IPPROTO_UDP", TypeSet.new(ElixirTypes.type_integer()))

:ip_protocol ->
"""
@@ -475,7 +475,7 @@ defmodule Honey.Translator do
}
"""
|> gen()
|> TranslatedCode.new(return_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(return_var, TypeSet.new(ElixirTypes.type_integer()))

:destination_port ->
"""
@@ -489,7 +489,7 @@ defmodule Honey.Translator do
}
"""
|> gen()
|> TranslatedCode.new(return_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(return_var, TypeSet.new(ElixirTypes.type_integer()))

:set_destination_port ->
[port] = params
@@ -505,7 +505,7 @@ defmodule Honey.Translator do
}
"""
|> gen()
|> TranslatedCode.new(port_var.return_var_name, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(port_var.return_var_name, TypeSet.new(ElixirTypes.type_integer()))

:h_source ->
"""
@@ -516,7 +516,7 @@ defmodule Honey.Translator do
"""
|> gen()
|> TranslatedCode.new(return_var, TypeSet.new(ElixirType.type_void()))
|> TranslatedCode.new(return_var, TypeSet.new(ElixirTypes.type_void()))
end
end

@@ -527,14 +527,14 @@ defmodule Honey.Translator do
return XDP_DROP;
"""
|> gen()
|> TranslatedCode.new("XDP_DROP", TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new("XDP_DROP", TypeSet.new(ElixirTypes.type_integer()))

:pass ->
"""
return XDP_PASS;
"""
|> gen()
|> TranslatedCode.new("XDP_PASS", TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new("XDP_PASS", TypeSet.new(ElixirTypes.type_integer()))
end
end

@@ -554,7 +554,7 @@ defmodule Honey.Translator do
# Dot operator to access ctx_arg
def to_c({{:., _, [{:ctx, _var_meta, var_context}, element]}, access_meta, _}, _context)
when is_atom(var_context) do
access_type = Keyword.get(access_meta, :types, TypeSet.new(ElixirType.type_any()))
access_type = Keyword.get(access_meta, :types, TypeSet.new(ElixirTypes.type_any()))
helper_var = unique_helper_var()

cond do
@@ -563,14 +563,14 @@ defmodule Honey.Translator do
int #{helper_var} = ctx_arg->#{element};
"""
|> gen()
|> TranslatedCode.new(helper_var, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(helper_var, TypeSet.new(ElixirTypes.type_integer()))

TypeSet.is_generic?(access_type) ->
"""
Generic #{helper_var} = {.type = INTEGER, .value.integer = ctx_arg->#{element}};
"""
|> gen()
|> TranslatedCode.new(helper_var, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(helper_var, TypeSet.new(ElixirTypes.type_any()))
end
end

@@ -712,7 +712,7 @@ defmodule Honey.Translator do
#{case_code}
"""
|> gen()
|> TranslatedCode.new(case_return_var, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(case_return_var, TypeSet.new(ElixirTypes.type_any()))
end

# Other structures
@@ -1062,12 +1062,12 @@ defmodule Honey.Translator do
String #{c_var_name} = #{helper_var_name};
"""

TypeSet.has_unique_type(var_typeset, ElixirType.type_binary()) ->
TypeSet.has_unique_type(var_typeset, ElixirTypes.type_binary()) ->
"""
String #{c_var_name} = #{helper_var_name};
"""

TypeSet.has_unique_type(var_typeset, ElixirType.type_void()) ->
TypeSet.has_unique_type(var_typeset, ElixirTypes.type_void()) ->
"""
void* #{c_var_name} = #{helper_var_name};
"""
@@ -1211,15 +1211,15 @@ defmodule Honey.Translator do
TranslatedCode.new(
"int #{var_name_in_c} = #{item};",
var_name_in_c,
TypeSet.new(ElixirType.type_integer())
TypeSet.new(ElixirTypes.type_integer())
)}

is_number(item) ->
{:ok,
TranslatedCode.new(
"Generic #{var_name_in_c} = {.type = DOUBLE, .value.double_precision = #{item}};",
var_name_in_c,
TypeSet.new(ElixirType.type_float())
TypeSet.new(ElixirTypes.type_float())
)}

# Considering only strings for now
@@ -1251,7 +1251,7 @@ defmodule Honey.Translator do
*string_pool_index = #{end_var_name} + 1;
""")

{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirType.type_bitstring()))}
{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirTypes.type_bitstring()))}

is_atom(item) ->
# TODO: Convert arbitrary atoms
@@ -1292,15 +1292,15 @@ defmodule Honey.Translator do
TranslatedCode.new(
"Generic #{var_name_in_c} = {.type = INTEGER, .value.integer = #{item}};",
var_name_in_c,
TypeSet.new(ElixirType.type_any())
TypeSet.new(ElixirTypes.type_any())
)}

is_number(item) ->
{:ok,
TranslatedCode.new(
"Generic #{var_name_in_c} = {.type = DOUBLE, .value.double_precision = #{item}};",
var_name_in_c,
TypeSet.new(ElixirType.type_any())
TypeSet.new(ElixirTypes.type_any())
)}

# Considering only strings for now
@@ -1332,7 +1332,7 @@ defmodule Honey.Translator do
*string_pool_index = #{end_var_name} + 1;
""")

{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirType.type_any()))}
{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirTypes.type_any()))}

is_atom(item) ->
# TODO: Convert arbitrary atoms
@@ -1352,7 +1352,7 @@ defmodule Honey.Translator do
end

code = "Generic #{var_name_in_c} = #{value};"
{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirType.type_any()))}
{:ok, TranslatedCode.new(code, var_name_in_c, TypeSet.new(ElixirTypes.type_any()))}

is_binary(item) ->
raise "We cannot convert binary yet."
@@ -1415,7 +1415,7 @@ defmodule Honey.Translator do

# Translates a block of code by calling to_c for each element in that block.
defp block_to_c({:__block__, _, exprs}, context) do
Enum.reduce(exprs, Honey.TranslatedCode.new(), fn expr, translated_so_far ->
Enum.reduce(exprs, Honey.Runtime.TranslatedCode.new(), fn expr, translated_so_far ->
translated_expr = to_c(expr, context)

%TranslatedCode{
@@ -1446,7 +1446,7 @@ defmodule Honey.Translator do
if TypeSet.is_generic?(rhs_in_c.return_var_type) do
"BINARY_OPERATION(#{return_name}, #{func_string}, #{lhs_in_c.return_var_name}, #{rhs_in_c.return_var_name})"
|> gen()
|> TranslatedCode.new(return_name, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(return_name, TypeSet.new(ElixirTypes.type_any()))

# RHS isn't generic, we need to get it to generic
else
@@ -1457,7 +1457,7 @@ defmodule Honey.Translator do
BINARY_OPERATION(#{return_name}, #{func_string}, #{lhs_in_c.return_var_name}, #{generic_rhs.return_var_name})
"""
|> gen()
|> TranslatedCode.new(return_name, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(return_name, TypeSet.new(ElixirTypes.type_any()))
end

# RHS is generic and lhs isn't
@@ -1469,7 +1469,7 @@ defmodule Honey.Translator do
BINARY_OPERATION(#{return_name}, #{func_string}, #{generic_lhs.return_var_name}, #{rhs_in_c.return_var_name})
"""
|> gen()
|> TranslatedCode.new(return_name, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(return_name, TypeSet.new(ElixirTypes.type_any()))

# Generics have been dealt with. Time to consider the rest.
TypeSet.is_integer?(lhs_in_c.return_var_type) and
@@ -1485,12 +1485,12 @@ defmodule Honey.Translator do
}
"""
|> gen()
|> TranslatedCode.new(return_name, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(return_name, TypeSet.new(ElixirTypes.type_any()))

_ ->
"int #{return_name} = #{lhs_in_c.return_var_name} #{function} #{rhs_in_c.return_var_name};"
|> gen()
|> TranslatedCode.new(return_name, TypeSet.new(ElixirType.type_integer()))
|> TranslatedCode.new(return_name, TypeSet.new(ElixirTypes.type_integer()))
end

true ->
@@ -1511,7 +1511,7 @@ defmodule Honey.Translator do
#{generic_var}.type = INTEGER; #{generic_var}.value.integer = #{typed_var.return_var_name};
"""

TypeSet.has_unique_type(typed_var.return_var_type, ElixirType.type_boolean()) ->
TypeSet.has_unique_type(typed_var.return_var_type, ElixirTypes.type_boolean()) ->
raise "TODO"

TypeSet.is_string?(typed_var.return_var_type) ->
@@ -1520,18 +1520,18 @@ defmodule Honey.Translator do
#{generic_var}.type = STRING; #{generic_var}.value.string = #{typed_var.return_var_name};
"""

TypeSet.has_unique_type(typed_var.return_var_type, ElixirType.type_binary()) ->
TypeSet.has_unique_type(typed_var.return_var_type, ElixirTypes.type_binary()) ->
raise "TODO"

TypeSet.has_unique_type(typed_var.return_var_type, ElixirType.type_void()) ->
TypeSet.has_unique_type(typed_var.return_var_type, ElixirTypes.type_void()) ->
raise "A void* type can't be translated to Generic. Make sure not to use it in tuples or the return of case/cond/if."

true ->
IO.inspect(typed_var)
raise "TODO"
end
|> gen()
|> TranslatedCode.new(generic_var, TypeSet.new(ElixirType.type_any()))
|> TranslatedCode.new(generic_var, TypeSet.new(ElixirTypes.type_any()))
end
end
end
229 changes: 0 additions & 229 deletions lib/honey/elixir_types.ex

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
defmodule Honey.ConstantPropagation do
defmodule Honey.Optimization.ConstantPropagation do
@moduledoc """
Executes Constant Propagation optimization in the elixir AST of the source program.
"""
import Honey.Utils, only: [var_to_key: 1, is_var: 1]
import Honey.Utils.Core, only: [var_to_key: 1, is_var: 1]

@doc """
Guard for constant values.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
defmodule Honey.DCE do
defmodule Honey.Optimization.DeadCodeElimination do
@moduledoc """
Executes Dead Code Elimination in the elixir AST of the source program.
"""
import Honey.Utils, only: [var_to_key: 1, is_var: 1, is_constant: 1]
import Honey.Utils.Core, only: [var_to_key: 1, is_var: 1, is_constant: 1]

@doc """
Runs Dead Code Elimination given an elixir AST.
23 changes: 23 additions & 0 deletions lib/honey/optimization/optimizer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Honey.Optimization.Optimizer do
@moduledoc """
Module to define and run the optimization pipeline that runs over elixirs AST.
"""
alias Honey.Analysis.SemanticAnalysis
alias Honey.Optimization.ConstantPropagation
alias Honey.Optimization.DeadCodeElimination
alias Honey.Optimization.TypePropagation

@doc """
Runs the optimization and analysis steps.
"""
def run(fun_def, arguments, env) do
fun_def
|> SemanticAnalysis.run()
|> ConstantPropagation.run()
|> DeadCodeElimination.run()
|> TypePropagation.run(arguments, env)

# |> Honey.Analysis.AstSize.output(env, " - Final")
# |> IO.inspect()
end
end
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
defmodule Honey.TypePropagation do
defmodule Honey.Optimization.TypePropagation do
@moduledoc """
Propagates the type of variables throughout the elixir AST of the source program.
Currently, it can exclusively execute in codes that only contains simple pattern matches, that is,
the left-hand side should solely comprise a simple variable and should not be enclosed within a more
complex structure, such as a tuple or array.
"""
# alias Mix.Tasks.Lsp.DataModel.Type wasn't moved in
alias Honey.ElixirType
alias Honey.Info
alias Honey.Analysis.ElixirTypes
alias Honey.Runtime.Info
alias Honey.TypeSet

import Honey.Utils, only: [var_to_key: 1, is_var: 1, is_constant: 1, var_to_atom: 1]
import Honey.Utils.Core, only: [var_to_key: 1, is_var: 1, is_constant: 1, var_to_atom: 1]

@doc """
This function executes type propagation on an Elixir AST.
@@ -68,7 +68,7 @@ defmodule Honey.TypePropagation do
end

defp get_types_of_arguments(_sec_module) do
[ElixirType.new(:type_ctx)]
[ElixirTypes.new(:type_ctx)]
# TODO: This will be implemented in the SEC file
end

@@ -91,25 +91,25 @@ defmodule Honey.TypePropagation do
type =
cond do
is_float(seg) ->
ElixirType.type_float()
ElixirTypes.type_float()

is_number(seg) ->
ElixirType.type_integer()
ElixirTypes.type_integer()

is_atom(seg) ->
ElixirType.type_atom()
ElixirTypes.type_atom()

is_binary(seg) ->
ElixirType.type_binary()
ElixirTypes.type_binary()

is_function(seg) ->
ElixirType.type_function()
ElixirTypes.type_function()

is_list(seg) ->
ElixirType.type_list()
ElixirTypes.type_list()

is_tuple(seg) ->
ElixirType.type_tuple()
ElixirTypes.type_tuple()

true ->
IO.puts("Type inferece: Could not identify the type of the structure:")
@@ -124,8 +124,8 @@ defmodule Honey.TypePropagation do
lhs_types = get_typeset_from_segment(lhs, context)
rhs_typeset = get_typeset_from_segment(rhs, context)

type_integer = ElixirType.type_integer()
type_float = ElixirType.type_float()
type_integer = ElixirTypes.type_integer()
type_float = ElixirTypes.type_float()

cond do
function == :+ or
@@ -147,7 +147,7 @@ defmodule Honey.TypePropagation do
type_float

_ ->
ElixirType.type_invalid()
ElixirTypes.type_invalid()
end
end
|> TypeSet.new()
@@ -171,54 +171,54 @@ defmodule Honey.TypePropagation do
TypeSet.new(type_float)

_ ->
TypeSet.new(ElixirType.type_invalid())
TypeSet.new(ElixirTypes.type_invalid())
end
end
|> TypeSet.new()
end
|> Enum.reduce(TypeSet.new(), &TypeSet.union/2)

function == :== or function == :=== or function == :!= or function == :!== ->
TypeSet.new(ElixirType.type_boolean())
TypeSet.new(ElixirTypes.type_boolean())

true ->
raise "Type propagation: Erlang function not supported: #{Atom.to_string(function)}"
end
end

defp extract_types_from_segment({{:., _, [Honey.Bpf_helpers, function]}, _, _params}, _context) do
defp extract_types_from_segment({{:., _, [Honey.BpfHelpers, function]}, _, _params}, _context) do
# # TODO: Check if function exists
# func_type = apply(Honey.Bpf_helpers, function, params)
# func_type = apply(Honey.BpfHelpers, function, params)

# if(!func_type) do
# TypeSet.new()
# else
# TypeSet.new(func_type)
# end
case function do
:bpf_printk -> TypeSet.new(ElixirType.type_integer())
:bpf_get_current_pid_tgid -> TypeSet.new(ElixirType.type_integer())
:bpf_map_update_elem -> TypeSet.new(ElixirType.type_integer())
:bpf_map_lookup_elem -> TypeSet.new(ElixirType.type_integer())
:bpf_printk -> TypeSet.new(ElixirTypes.type_integer())
:bpf_get_current_pid_tgid -> TypeSet.new(ElixirTypes.type_integer())
:bpf_map_update_elem -> TypeSet.new(ElixirTypes.type_integer())
:bpf_map_lookup_elem -> TypeSet.new(ElixirTypes.type_integer())
_ -> TypeSet.new()
end
end

defp extract_types_from_segment({{:., _, [Honey.XDP, function]}, _, _params}, _context) do
case function do
:drop -> TypeSet.new(ElixirType.type_integer())
:pass -> TypeSet.new(ElixirType.type_integer())
:drop -> TypeSet.new(ElixirTypes.type_integer())
:pass -> TypeSet.new(ElixirTypes.type_integer())
end
end

defp extract_types_from_segment({{:., _, [Honey.Ethhdr, function]}, _, _params}, _context) do
case function do
:init -> TypeSet.new(ElixirType.type_invalid())
:const_udp -> TypeSet.new(ElixirType.type_integer())
:ip_protocol -> TypeSet.new(ElixirType.type_integer())
:destination_port -> TypeSet.new(ElixirType.type_integer())
:set_destination_port -> TypeSet.new(ElixirType.type_integer())
:h_source -> TypeSet.new(ElixirType.type_void())
:init -> TypeSet.new(ElixirTypes.type_invalid())
:const_udp -> TypeSet.new(ElixirTypes.type_integer())
:ip_protocol -> TypeSet.new(ElixirTypes.type_integer())
:destination_port -> TypeSet.new(ElixirTypes.type_integer())
:set_destination_port -> TypeSet.new(ElixirTypes.type_integer())
:h_source -> TypeSet.new(ElixirTypes.type_void())
_ -> TypeSet.new()
end
end
@@ -244,16 +244,16 @@ defmodule Honey.TypePropagation do
:type_ctx ->
case field do
:data ->
TypeSet.put_type(typeset, ElixirType.new(:type_ctx_data))
TypeSet.put_type(typeset, ElixirTypes.new(:type_ctx_data))

:id ->
TypeSet.put_type(typeset, ElixirType.type_integer())
TypeSet.put_type(typeset, ElixirTypes.type_integer())

:sig ->
TypeSet.put_type(typeset, ElixirType.type_integer())
TypeSet.put_type(typeset, ElixirTypes.type_integer())

:pid ->
TypeSet.put_type(typeset, ElixirType.type_integer())
TypeSet.put_type(typeset, ElixirTypes.type_integer())

_ ->
raise "Invalid field access. Tried accessing inexisting field '#{field}' of variable '#{var_name}'."
@@ -299,7 +299,7 @@ defmodule Honey.TypePropagation do
rhs_typeset = get_typeset_from_segment(rhs, tp_context)

typed_rhs = add_types_to_segment(rhs, rhs_typeset)
typed_lhs = add_types_to_segment(lhs, TypeSet.new(ElixirType.type_invalid()))
typed_lhs = add_types_to_segment(lhs, TypeSet.new(ElixirTypes.type_invalid()))

typed_args = {typed_lhs, typed_rhs}

@@ -333,7 +333,7 @@ defmodule Honey.TypePropagation do
{_rhs_typeset, {typed_lhs, typed_rhs}, tp_context} =
resolve_typeset_from_match([lhs, rhs], tp_context)

rhs_typeset = TypeSet.new(ElixirType.type_tuple())
rhs_typeset = TypeSet.new(ElixirTypes.type_tuple())
typed_lhs = List.to_tuple(typed_lhs)
typed_rhs = List.to_tuple(typed_rhs)
{rhs_typeset, {typed_lhs, typed_rhs}, tp_context}
@@ -353,14 +353,14 @@ defmodule Honey.TypePropagation do
end)

{typed_lhs, typed_rhs} = Enum.unzip(typed_match)
rhs_typeset = TypeSet.new(ElixirType.type_list())
rhs_typeset = TypeSet.new(ElixirTypes.type_list())
{rhs_typeset, {typed_lhs, typed_rhs}, tp_context}
end
end

defmodule TPContext do
alias Honey.TypeSet
import Honey.Utils, only: [is_var: 1, var_to_atom: 1]
import Honey.Utils.Core, only: [is_var: 1, var_to_atom: 1]

# var_types is a Keyword list.
defstruct var_types: [], env: nil
20 changes: 0 additions & 20 deletions lib/honey/optimizer.ex

This file was deleted.

2 changes: 1 addition & 1 deletion lib/honey/info.ex → lib/honey/runtime/info.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Honey.Info do
defmodule Honey.Runtime.Info do
@moduledoc """
A module for getting hard/inconvenient information to the rest of the project.
"""
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
defmodule Honey.TranslatedCode do
defmodule Honey.Runtime.TranslatedCode do
@moduledoc """
Defines the struct that keeps the translated code and its constructor.
"""
alias Honey.{ElixirType, TypeSet}
alias Honey.Analysis.ElixirTypes
alias Honey.TypeSet

defstruct [:code, :return_var_name, :return_var_type]

@@ -13,7 +14,7 @@ defmodule Honey.TranslatedCode do
def new(
code \\ "",
return_var_name \\ "0var_name_err",
return_var_type \\ TypeSet.new(ElixirType.type_any())
return_var_type \\ TypeSet.new(ElixirTypes.type_any())
) do
%__MODULE__{code: code, return_var_name: return_var_name, return_var_type: return_var_type}
end
7 changes: 7 additions & 0 deletions lib/honey/type.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Honey.Type do
defstruct c_type: nil, e_type: nil
defguard is_type(var) when is_struct(var, Honey.Analysis.ElixirTypes) or is_struct(var, Honey.Analysis.ElixirTypes)

def receive_type(type) when is_type(type) do
end
end
106 changes: 106 additions & 0 deletions lib/honey/typeset.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
defmodule Honey.TypeSet do
@moduledoc """
This module manages the information regarding the types that a variable can assume at
a point in the code. Uses Honey.Analysis.ElixirTypes to represent the possible types.
"""
alias Honey.Analysis.ElixirTypes

import Honey.Utils.Core, only: [is_var: 1]

defstruct types: MapSet.new()

def new(arr \\ [])

def new(arr) when is_list(arr) do
%__MODULE__{types: MapSet.new(arr)}
end

def new(type = %ElixirTypes{}) do
%__MODULE__{types: MapSet.new([type])}
end

def new(typeset = %__MODULE__{}) do
typeset
end

def new(mapset = %MapSet{}) do
%__MODULE__{types: mapset}
end

def put_type(typeset = %__MODULE__{}, type = %ElixirTypes{}) do
%__MODULE__{typeset | types: MapSet.put(typeset.types, type)}
end

def union(type_set_a = %__MODULE__{}, type_set_b = %__MODULE__{}) do
MapSet.union(type_set_a.types, type_set_b.types)
|> new()
end

def type_is_unique(set = %__MODULE__{}) do
size(set) == 1
end

def has_type(set = %__MODULE__{}, type = %ElixirTypes{}) do
MapSet.member?(set.types, type)
end

def has_unique_type(set = %__MODULE__{}, type = %ElixirTypes{}) do
size(set) == 1 and has_type(set, type)
end

def is_generic?(set = %__MODULE__{}) do
size(set) > 1 or size(set) == 0 or has_type(set, ElixirTypes.type_any())
end

def is_integer?(set = %__MODULE__{}) do
has_unique_type(set, ElixirTypes.type_integer())
end

def is_string?(set = %__MODULE__{}) do
has_unique_type(set, ElixirTypes.type_bitstring())
end

def size(set = %__MODULE__{}) do
MapSet.size(set.types)
end

def is_any(type_set = %__MODULE__{}) do
size(type_set) == 0
end

def get_typeset_from_var_ast({_, meta, _} = var) when is_var(var) do
Keyword.get(meta, :types, __MODULE__.new())
end

def get_typeset_from_var_ast(_) do
__MODULE__.new()
end

defimpl Enumerable do
def count(type_set) do
{:ok, MapSet.size(type_set.types)}
end

def member?(type_set, val) do
{:ok, MapSet.member?(type_set.types, val)}
end

def slice(type_set) do
size = MapSet.size(type_set.types)
{:ok, size, &MapSet.to_list/1}
end

def reduce(type_set, acc, fun) do
Enumerable.List.reduce(MapSet.to_list(type_set.types), acc, fun)
end
end

defimpl Inspect do
import Inspect.Algebra

def inspect(type_set, opts) do
opts = %Inspect.Opts{opts | charlists: :as_lists}
concat(["TypeSet.new(", Inspect.List.inspect(MapSet.to_list(type_set.types), opts), ")"])
end
end
end
2 changes: 1 addition & 1 deletion lib/honey/utils.ex → lib/honey/utils/core.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Honey.Utils do
defmodule Honey.Utils.Core do
@moduledoc """
Contains utility functions used across Honey-Potion.
"""
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Honey.Directories do
defmodule Honey.Utils.Directories do
@moduledoc """
Creates directories used in the user directory and returns commonly used directories.
"""
6 changes: 3 additions & 3 deletions lib/honey/guard.ex → lib/honey/utils/guard.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
defmodule Honey.Guard do
defmodule Honey.Utils.Guard do
@moduledoc """
Contains functions used to guard certain parts of code.
"""
alias Honey.Utils
alias Honey.Utils.Core

@doc """
Guarantees that we have a main module to translate. Also returns its definition.
@@ -13,7 +13,7 @@ defmodule Honey.Guard do

# If the main function isn't defined raise an error.
if !(main_def = Module.get_definition(env.module, {target_func, target_arity})) do
Utils.compile_error!(
Core.compile_error!(
env,
"Module #{env.module} is using eBPF but does not contain #{target_func}/#{target_arity}."
)
12 changes: 6 additions & 6 deletions lib/honey/write.ex → lib/honey/utils/write.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
defmodule Honey.Write do
defmodule Honey.Utils.Write do
@moduledoc """
Contains functions used to write output files into the right directories.
"""
alias Honey.Directories
alias Honey.Utils
alias Honey.Utils.Directories
alias Honey.Utils.Core

@doc """
Writes all of the relevant files post-translation, which include module.c and module.bpf.c. Also makes sure write directories exist.
@@ -19,8 +19,8 @@ defmodule Honey.Write do
Writes the .bpf.c output file. This is the part that we translate from elixir code.
"""
def write_backend_code(env, backend_code) do
mod_name = Utils.module_name(env)
clang_format = Utils.clang_format(env)
mod_name = Core.module_name(env)
clang_format = Core.clang_format(env)

backend_path = Directories.userdir(env) |> Path.join("src/#{mod_name}.bpf.c")

@@ -38,7 +38,7 @@ defmodule Honey.Write do
Writes the frontend code into the right directory.
"""
def write_frontend_code(env, frontend_code) do
mod_name = Utils.module_name(env)
mod_name = Core.module_name(env)
userdir = Directories.userdir(env)

File.write(userdir |> Path.join("./src/#{mod_name}.c"), frontend_code)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule CompileBPF do
defmodule Honey.Mix.Tasks.CompileBPF do
use Mix.Task

def run(_) do
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -33,9 +33,9 @@ defmodule Honey.MixProject do

defp aliases do
[
# The CompileBPF.run function currently has no use. It has been left as a reference of
# The Honey.Mix.Tasks.CompileBPF.run function currently has no use. It has been left as a reference of
# where code can be added for it to be executed before the compilation step of Elixir.
compile: ["compile", &CompileBPF.run/1]
compile: ["compile", &Honey.Mix.Tasks.CompileBPF.run/1]
]
end