It's been a while since I've thought about this, but I recently came across 
Araq's [ormin](https://github.com/Araq/ormin), and noticed something that took 
me by surprise. This post isn't really a question or issue, I just wanted to 
get my thoughts out there.

Ormin's encompassing macro, as far as I can tell with my uneducated knowledge 
about the subject, generates a Nim source file for the client, and an AST node 
for the server, meaning the Nim file managed by the user is the server.

I've had the opposite idea for multiple applications, where 1 file collects AST 
from other files and operates on it. My first use case (that I never developed) 
was for a state-based game:
    
    
    # main.nim
    macro generateStates(sharedFile, statesDir: static[string]) =
      # generate StateKind enum, State object variant, pollInputs and render 
procs embedding code from the state modules
    
    generateStates("shared.nim", "states/")
    
    const defaultState = MainMenu
    
    proc main =
      var shared: Shared
      var state: State = initialize(defaultState, shared)
      while not shared.endLoop:
        pollInputs(state, shared)
        if 1/60 second passes:
          render(state, shared)
    
    
    Run
    
    
    # shared.nim
    type Shared* = object
      window*: Window
      endLoop*: bool
    
    
    Run
    
    
    # states/main_menu.nim
    # generates a ref object to put in the state object variant for the 
variables and constants are gensym'd into main
    var hoveredButton: int
    const Buttons = ["Play", "Exit"]
    texture logoTexture, "res/logo_texture.png" # can dynamically or statically 
load texture, although both can be expressed without the shorthand
    
    input:
      hoveredButton = locateButton(mouseX, mouseY)
      if mouseClicked:
        case hoveredButton
        of 0:
          state = initialize(Gameplay, shared)
        of 1:
          shared.endLoop = true
    
    render:
      render(logoTexture, x, y, w, h)
      for i, b in Buttons:
        if i == hoveredButton:
          strokeColor = green
        else:
          strokeColor = black
        renderText(b, ...)
    
    
    Run

This could even support substates, say the Gameplay loop would have its own 
shared object and generator macro and have the states GameplayMenu, 
GameplayInventory and GameplayAction in another directory like 
states/gameplay/menu.nim.

Problems with this specific example include dealing with AST hygiene, code 
size, performance (I would make it generate a giant function instead of using 
function pointers, probably not the best idea), the code could turn into soggy 
spaghetti... I could try to give another example
    
    
    # main.nim
    generateSubcommands("subcmds/")
    
    var args = parse(commandLineParams())
    
    chooseSubcommand(args)
    
    
    Run
    
    
    # subcmds/create_project.nim
    writeFile("project.cfg", """
    name = "new project"
    version = 1.0""")
    
    
    Run

I'm wondering if this design pattern in general is a good idea. Does it 
decrease productivity or increase it? Do you guys use something similar or do 
you have something to add? If I ever do something with these thoughts instead 
of just talk about them I'll make sure to come back to this post and share it

Reply via email to