Skip to content

Commit

Permalink
create_foot can accept a tuple of one element. (@feet ) returns an em…
Browse files Browse the repository at this point in the history
…pty vector of StockAndFlow0
  • Loading branch information
neonWhiteout committed Sep 27, 2023
1 parent 16cde76 commit 2d5b2f8
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 23 deletions.
28 changes: 19 additions & 9 deletions src/Syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -951,8 +951,10 @@ Create a foot with S => N syntax, where S is stock, N is sum variable.
```
"""
macro foot(block::Expr)
Base.remove_linenums!(block)
return create_foot(block)
escaped_block = Expr(:quote, block)
quote
create_foot($(escaped_block))
end
end


Expand All @@ -976,14 +978,23 @@ end
"""
macro feet(block::Expr)
Base.remove_linenums!(block)
@match block begin
quote
$((block...))
end => map(create_foot, block) # also matches empty
Expr(e, _...) => [create_foot(block)] # this also matches the above, so it's necessary this comes second.
escaped_block = Expr(:quote, block)
quote
inner_block = $escaped_block
@match inner_block begin
quote
$((inner_block...))
end => map(create_foot, inner_block) # also matches empty
Expr(e, _...) => [create_foot(inner_block)] # this also matches the above, so it's necessary this comes second.
end
end
end

macro feet()
quote
Vector{StockAndFlow0}()
end
end

"""
create_foot(block :: Expr)
Expand All @@ -1004,10 +1015,9 @@ multiple_links = @foot A => B, A => B # will have two links from A to B.
"""
function create_foot(block::Expr)
@match block.head begin

:tuple => begin
if isempty(block.args) # case for create_foot(:())
error("Cannot create foot with no arguments.")
error("Cannot create foot with zero arguments.")
end
foot_s = Vector{Symbol}()
foot_sv = Vector{Symbol}()
Expand Down
27 changes: 13 additions & 14 deletions test/Syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using Base: is_unary_and_binary_operator
using Test
using StockFlow
using StockFlow.Syntax
using StockFlow.Syntax: is_binop_or_unary, sum_variables, infix_expression_to_binops, fnone_value_or_vector, extract_function_name_and_args_expr, is_recursive_dyvar, create_foot, apply_flags, substitute_symbols
using StockFlow.Syntax: is_binop_or_unary, sum_variables, infix_expression_to_binops, fnone_value_or_vector, extract_function_name_and_args_expr, is_recursive_dyvar, create_foot, apply_flags, substitute_symbols, DSLArgument

@testset "Stratification DSL" begin
include("syntax/Stratification.jl")
Expand Down Expand Up @@ -296,16 +296,14 @@ end
end

@testset "foot syntax disallows invalid feet" begin # note, @feet calls create_foot for each line, so this should apply to both @foot and @feet
@test_throws Exception create_foot(:(A => B => C)) # Invalid syntax for second argument of foot: B => C
@test_throws Exception create_foot(:(oooo2 + f => C)) # Invalid syntax for first argument of foot: oooo2 + f
@test_throws Exception create_foot(:(A + B)) # Invalid syntax function for foot: +
@test_throws Exception create_foot(:(=>)) # no method matching create_foot(::Symbol)
@test_throws Exception create_foot(:(=>(A, B, C, D)))
@test_throws Exception create_foot(:())
@test_throws Exception create_foot(:(([]) => ()))

@test_throws Exception create_foot(:(A => B, P => Q, C))
@test_throws Exception create_foot(:(() => E, () => (K,)))
@test_throws ErrorException @foot A => B => C # Invalid syntax for second argument of foot: B => C
@test_throws ErrorException @foot oooo2 + f => C # Invalid syntax for first argument of foot: oooo2 + f
@test_throws ErrorException @foot A + B # Invalid syntax function for foot: +
@test_throws ErrorException @foot =>(A, B, C, D)
@test_throws ErrorException @foot ()
@test_throws ErrorException @foot ([]) => ()
@test_throws MethodError @foot A => B, P => Q, C # Issue here is it tries calling match_foot_format with a symbol
@test_throws ErrorException @foot () => E, () => (K,)

end

Expand Down Expand Up @@ -344,12 +342,13 @@ end
foot(:J, (:K, :Q), (:J => :K, :J => :Q))
]

@test (@feet ) == Vector{StockAndFlow0}();
end

@testset "feet syntax fails on invalid feet" begin # mostly to check that an exception is thrown even if some of the feet are valid.
@test_throws Exception @eval @feet A => B => C # eval required so the errors occur at runtime, rather than at compilation
@test_throws Exception @eval @feet begin A => B; =>(D,E,F) end
@test_throws Exception @eval @feet begin A => B; 1 => 2; end
@test_throws ErrorException @feet A => B => C
@test_throws ErrorException @feet begin A => B; =>(D,E,F) end
@test_throws ErrorException @feet begin A => B; 1 => 2; end
end

###########################
Expand Down

0 comments on commit 2d5b2f8

Please sign in to comment.