From ab698d680cf8ea1974ba30756c9fe2f7af56b20d Mon Sep 17 00:00:00 2001
From: Daniel Vedder <daniel.vedder@idiv.de>
Date: Wed, 14 Dec 2022 23:59:27 +0100
Subject: [PATCH] Rewrote @species

The first version generally did what it was supposed to, but was overly
complicated and brittle, because it basically did its own parsing.
This version simply wraps the user code in a function and uses @locals
to access the ready-parsed variables. This is not only much cleaner,
but also gives the user more of what he expects (e.g. the ability to
reference previously defined variables).

I had actually tried this approach before, but only got it to work
once I understood how @locals works under the hood, plus a lot of other
Julia internals. So I now not only have more elegant code, I also
learnt quite a bit - a good win :-)
---
 src/nature/species.jl | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/nature/species.jl b/src/nature/species.jl
index 433fe31..9cef463 100644
--- a/src/nature/species.jl
+++ b/src/nature/species.jl
@@ -3,33 +3,33 @@
 ### This file implements the macros needed for the species DSL.
 ###
 
-#TODO configure species traits via a separate TOML file
+#XXX configure species traits via a separate TOML file?
 
 ##TODO replace the current registerspecies()
 function registerspecies(speciesdict)
-    speciesdict["testphase"]()
+    println(speciesdict)
+    processeddict = Dict{String,Any}()
+    for k in keys(speciesdict)
+        processeddict[string(k)] = speciesdict[k]
+    end
+    processeddict["testphase"]()
 end
 
+##TODO docstring
 macro species(name, body)
-    speciesdict = gensym()
+    speciesfun = gensym()
     quote
-        $speciesdict = Dict{String, Any}("name"=>string($(QuoteNode(name))))
-        for line in $(body.args)
-            (typeof(line) == LineNumberNode) && continue
-            if line.head == :macrocall
-                line = macroexpand($(__module__), line)
-                line.args[2] = Core.eval($(__module__), line.args[2])
-            end
-            if line.head == :(=)
-                $speciesdict[string(line.args[1])] = line.args[2]
-            end
+        Core.@__doc__ $speciesfun = function()
+            $(esc(:name)) = string($(QuoteNode(name)))
+            $(esc(body))
+            return Base.@locals
         end
-        registerspecies($speciesdict)
+        registerspecies($speciesfun())
     end
 end
 
+##TODO docstring
 macro phase(name, body)
-    #:($(esc(name)) = function() $body end) #for testing
     :($(esc(name)) = function(animal::Animal, model::AgentBasedModel) $body end)
+    #:($(esc(name)) = function() $body end) #for testing
 end
-
-- 
GitLab