From 2d5b2f869d5be194590f2d4bd4ea42f32d498736 Mon Sep 17 00:00:00 2001 From: Thomas Purdy Date: Tue, 26 Sep 2023 21:54:36 -0600 Subject: [PATCH] create_foot can accept a tuple of one element. (@feet ) returns an empty vector of StockAndFlow0 --- src/Syntax.jl | 28 +++++++++++++++++++--------- test/Syntax.jl | 27 +++++++++++++-------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/Syntax.jl b/src/Syntax.jl index 7b77f456..b14566bb 100644 --- a/src/Syntax.jl +++ b/src/Syntax.jl @@ -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 @@ -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) @@ -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}() diff --git a/test/Syntax.jl b/test/Syntax.jl index d0fb2d5b..22c55e64 100755 --- a/test/Syntax.jl +++ b/test/Syntax.jl @@ -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") @@ -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 @@ -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 ###########################