Skip to content

Commit

Permalink
Merge pull request #22 from co1emi11er2/fix-func-not-found
Browse files Browse the repository at this point in the history
Fix func not found
  • Loading branch information
co1emi11er2 authored Dec 5, 2024
2 parents 1ab0a71 + ffa96fa commit 03590c6
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Latexify = "^0.16.4"
MacroTools = "0.5"
PrecompileTools = "1.2"
Revise = "3.5"
TestHandcalcFunctions = "0.2.2"
TestHandcalcFunctions = "0.2.3"
Unitful = "1.19"
UnitfulLatexify = "^1.6.4"
julia = "1.10"
Expand Down
3 changes: 1 addition & 2 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ x = 0
y = sin(x)
z = cos(x)
I_x, I_y = TestHandcalcFunctions.calc_Is(5, 15)
end not_funcs = [sin cos]
end not_funcs = [:sin :cos]
```

In the above example `sin` and `cos` were passed over and `calc_Is` was not. As you can see, the `calc_Is` function was a function that called other functions, and the `@handcalcs` macro continued to step into each function to unroll all expressions. Please see below for a list of the current functions that are passed over automatically. Please submit a pull request if you would like to add more generic math functions that I have left out.
Expand All @@ -139,7 +139,6 @@ set_handcalcs(not_funcs = [:foo :bar :baz])
Current Limitations for `@handcalcs`

- I believe the function needs to be defined in another package. The @code_expr macro from CodeTracking.jl does not see functions in Main for some reason.
- If the function has other function calls within it's body that are not available in Main, then the macro will error.

## Changing Default Settings:

Expand Down
4 changes: 4 additions & 0 deletions src/handcalc_marco.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ function check_not_funcs(f, kwargs)
if defaults != []
push!(not_funcs, defaults...)
end
if Meta.isexpr(f, :.)
f_new = f.args[end].value
return f_new not_funcs
end
return f not_funcs
end

Expand Down
2 changes: 1 addition & 1 deletion src/handcalcs_macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function clean_expr(expr, len, spa)
end

expr = split(expr, " = ") |> unique |> x -> join(x, " = ")[1:end-1] # removes any redundant parts, and removes space at the end
expr = replace(expr, " = "=>"&=", count=1) # add alignment
expr = replace(expr, " = "=>" &= ", count=1) # add alignment
expr = len == :long ? replace(expr, " = "=>"\n\\\\[$spa" *"pt]\n&= ", count=2) : expr

# change "==" back to "="
Expand Down
33 changes: 29 additions & 4 deletions src/handfunc_macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ macro handfunc(expr, kwargs...)
var = esc(expr.args[1])
eq = esc(expr.args[2])
return quote
found_module = $(esc(:(Handcalcs.@which $(expr.args[2])))).module
found_func = $(esc(:(Handcalcs.@code_expr $(expr.args[2]))))
func_args = $(esc(:(Handcalcs.@func_vars $(expr.args[2]))))
latex_eq = handfunc(found_func, func_args, $kwargs)
latex = @eval $(Expr(:$, :latex_eq))
latex_eq = handfunc(found_module, found_func, func_args, $kwargs)
latex = @eval #=found_module=# $(Expr(:$, :latex_eq))
$var = $eq
latex
end
Expand All @@ -41,18 +42,42 @@ macro func_vars(expr)
return esc(Meta.quot(expr_numeric))
end

function handfunc(found_func, func_args, kwargs)
function handfunc(found_module, found_func, func_args, kwargs)
func_body = remove_return_statements(found_func.args[2])
func_body = unblock(func_body)
func_body = rmlines(func_body)

func_body = _walk_func_body(func_body, found_module)
kw_dict, pos_arr = _initialize_kw_and_pos_args(found_func, func_args)
return_expr = _initialize_expr(kw_dict, pos_arr)
push!(return_expr.args[2].args, :(@handcalcs $(func_body) $(kwargs...)))
# ret = @eval eval_module $return_expr
return return_expr
end

function _walk_func_body(expr::Expr, found_module)
# found_module can be Foo or Foo.Bar need to parse it correctly
found_module_string = string(found_module)

prewalk(expr) do x
if @capture(x, f_(args__))
len = length(collect(Leaves(f)))
if len == 1
if isdefined(Main, f) # should really be `Base` but `Main` is used for now
x
else
new_x = Meta.parse(found_module_string * "." * string(x))
new_x
end
else
new_x = Meta.parse(found_module_string * "." * string(x))
new_x
end
else
x
end
end
end

function _initialize_kw_and_pos_args(found_func, func_args)
found_func_args = found_func.args[1]
found_kw_dict, found_pos_arr = parse_func_args(found_func_args, _extract_kw_args, _extract_arg)
Expand Down
9 changes: 5 additions & 4 deletions test/handcalcs_macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ end not_funcs = [calc_Ix; calc_Iy]
# ***************************************************
# ***************************************************
expected = L"$\begin{aligned}
I&=\begin{cases}
I &= \begin{cases}
\frac{5 \cdot 15^{3}}{12} & \text{if } type = Ix\\
\frac{15 \cdot 5^{3}}{12} & \text{otherwise}
\end{cases} = \begin{cases}
Expand All @@ -253,10 +253,11 @@ calc = @handcalcs I= if type == :Ix
else
15 * 5^3/12
end
@test calc == expected

@test calc == replace(expected, "\r" => "") # for whatever reason the expected had addittional carriage returns (\r)

expected = L"$\begin{aligned}
I&=\begin{cases}
I &= \begin{cases}
\frac{5 \cdot 15^{3}}{12} & \text{if } Ix = Ix\\
\frac{15 \cdot 5^{3}}{12} & \text{otherwise}
\end{cases} = 1406.25
Expand All @@ -267,5 +268,5 @@ calc = @handcalcs I= if :Ix == :Ix
else
15 * 5^3/12
end
@test calc == expected
@test calc == replace(expected, "\r" => "") # for whatever reason the expected had addittional carriage returns (\r)
# ***************************************************
34 changes: 33 additions & 1 deletion test/handfunc_macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ calc_1 = @handcalcs y = sym_function(x)
# ***************************************************
# ***************************************************
expected = L"$\begin{aligned}
c &= a + b = 4 + 5 = 9
c2 &= a + b = 4 + 5 = 9
\end{aligned}$"
a = 4
b = 5
Expand Down Expand Up @@ -170,3 +170,35 @@ expected = L"$\begin{aligned}
calc = @handcalcs 5 + 6 + 7
@test calc == expected
# ***************************************************

# Check recursive functions as well as functions not in scope
# ***************************************************
# ***************************************************
expected = L"$\begin{aligned}
Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25
\\[10pt]
Iy &= \frac{h \cdot b^{expo}}{denominator} = \frac{15 \cdot 5^{3}}{12} = 156.25
\\[10pt]
c1 &= a \cdot b = 5 \cdot 15 = 75
\\[10pt]
c2 &= a + b = 5 + 15 = 20
\end{aligned}$"
calc = @handcalcs result = TestHandcalcFunctions.test_function_finder(5, 15)
@test calc == expected

expected = L"$\begin{aligned}
Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25
\\[10pt]
Iy &= \mathrm{calc}_{Iy}\left( h, b \right) = \mathrm{calc}_{Iy}\left( 15, 5 \right) = 156.25
\\[10pt]
c1, c2 &= \mathrm{\mathrm{\mathrm{TestHandcalcFunctions}\left( SubA \right)}\left( sub}_{{module\\_func} \right)}\left( a, b \right) = \mathrm{sub}_{module\_func}\left( 5, 15 \right) = \left[
\begin{array}{c}
75 \\
20 \\
\end{array}
\right]
\end{aligned}$"

calc = @handcalcs result = TestHandcalcFunctions.test_function_finder(5, 15) not_funcs = [:calc_Iy :sub_module_func]
@test calc == replace(expected, "\r" => "") # for whatever reason the expected had addittional carriage returns (\r)
# ***************************************************

2 comments on commit 03590c6

@co1emi11er2
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register

Release notes:

Added Feature

  • Now functions that are called within other functions should not have to be defined in main for unrolling to work!
    • there is one case if you have a function defined in Main, that is the same function name as one in another module (not in main), it will currently use the Main function. This could cause silent errors which is not good. However, this is a single word fix and will be changed in the future. Latexify doesn't parse Foo.bar(args...) well currently, so I wanted to keep it this way, but I may change this very soon anyway.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/120780

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.4.3 -m "<description of version>" 03590c6e653c048a6a26ab2ec35e811f33a9317a
git push origin v0.4.3

Please sign in to comment.