Hacker News new | past | comments | ask | show | jobs | submit login

I'm not sure exactly what you're asking, but I can answer at least part of it. You can build lists at compile time in Nim via the `static` statement or `compileTime` pragma. Eg:

  # using the pragma here, but we could use a 'static' block instead
  var cycles {.compileTime.}: int

  # ---

  proc doSomething =
    static:
      # invoked once at compile-time (at this definition)
      cycles += 1

  proc doSomethingGeneric[T] =
    static:
      # invoked once at compile-time (per unique generic call)
      cycles += 1

  macro doSomethingAtCompileTime(n): stmt =
    # invoked at compile-time (per call)
    let ncycles = int n.intVal
    cycles += ncycles

  # ---

  doSomething() # this call doesn't effect 'cycles', it's declaration does (+0)
  doSomething() # ditto (just here to prove a point) (+0)
  doSomethingGeneric[int]() # this call effects 'cycles' (+1)..
  doSomethingGeneric[int]() # ..but only once (+0)
  doSomethingGeneric[float]() # this call also effects 'cycles'  (+1)
  doSomethingAtCompileTime(5) # this call effects 'cycles'  (+5)
  doSomethingAtCompileTime(12) # ditto  (+12)

  static:
    echo cycles # prints '20'
I'm not sure this helps solve anything in NimES, but this can be really useful for meta-programming in general. For instance I'm using it to make an event system which generates efficient dispatch lists based on the types/procs defined. It's designed for game logic, to both minimize boiler-plate and dynamic dispatch. Ie, invocation it's type-specific and usually does not use function pointers per-instance, so smaller 'events' can be inlined. Plus, instances are generic (decoupled from object inheritance), and often don't require any header data. That combination should, in theory (still WIP), give devs a 'universal' way to model a broad range of game objects from heavy single-instance types to lightweight projectiles and particles. Here's an example for a little clarity:

  # note: 'impl', 'spawn', and 'invoke' are macros
  
  type
    Foo = object
      val: int
    
    Bar = object
      val: string
  
  impl Foo:
    proc update = echo "Foo: ", me.val
    proc render = echo "Rendering Foo!"
  
  impl Bar:
    proc update = echo "Bar: ", me.val
  
  spawn Foo(val:123)
  spawn Bar(val:"abc")
  
  invoke update
  invoke render
  invoke blah
  
  # ouptput:
  #   Foo: 123
  #   Bar: abc
  #   Rendering Foo!
  #   Invoke Error: No event 'blah' defined.
Perhaps that's not the best example to illustrate Nim's meta capabilities, but so far Nim is the only language I've come across that allows me to achieve this short of thing (at least, directly from user-code).



Thanks, seems like the thing I'm looking for.

If you look at line 531 of the CPU source code (as of today, anyway), there are multiple 256 byte tables that give instruction encodings, lengths, and cycle counts.

What I was asking is: "Is it possible to put these as a parameter of the 'op' macro so that it builds these tables automatically"

The answer might be "No" if e.g. a single op has multiple instruction encodings. But assume that there is only one encoding per op.

An equivalent question is - can static: sections assign to an array that will be available at runtime? From your example, the answer appears to be yes.


> can static: sections assign to an array that will be available at runtime?

The answer is yes, but it's a tad trickier than just accessing the compile-time list from run-time code (which doesn't make sense, and is illegal). Instead, use a macro to generate a bunch of run-time checks against a specific value. Eg:

  var eventNames {.compileTime.} = newSeq[string]()
  
  proc defineEvent(name:static[string]) =
    static:
      eventNames.add(name)
  
  macro checkDefined(name): stmt =
    # begin new statement
    result = newStmtList().add quote do:
      echo "Checking for '", `name`, "'"
    
    # loop over every known event name and
    # build a run-time 'if' check for each one.
    for n in eventNames:
      result.add quote do:
        if `n` == `name`:
          echo "Found it!"
  
  
  # add some events to compile-time list
  defineEvent("foo")
  defineEvent("bar")
  
  # define some runtime values
  let eventName1 = "foo"
  let eventName2 = "blah"
  
  # check runtime values againts compile-time list
  checkDefined(eventName1)
  checkDefined(eventName2)
  
  # output:
  #   Checking for 'foo'
  #   Found it!
  #   Checking for 'blah'
Note: This will inject a bunch of 'if' statements for each call to 'checkDefined', which might bloat your code.. it's probably better to make a macro which defines a proc, then just call that to check run-time values.. but I left those kinds of details out of this illustration for the sake of simplicity.


Thanks. I'm sure there's a way to promote a compile time seq into a constant runtime one. Might require some more macro trickery, though.


Err... what you said just reminded me of something, and I realized all the code I just showed you is really over-complicated and that Nim has much more straight forward options using `const`, like this:

  static:
    # define a compile-time list first
    var names = newSeq[string]()
    
    # add some values (at compile-time)
    names.add("foo")
    names.add("bar")

  # define the compiler vars as run-time const
  const runtimeNames = names

  # define some run-time variables
  var name1 = "foo"
  var name2 = "blah"

  # check runtime variables against const variable
  if runtimeNames.contains(name1): echo "Has Foo!"
  if runtimeNames.contains(name2): echo "Has Blah!"
Sorry about the rather winded (and bad example) replys :| But thanks for the conversation, it reminded me of this and now I have some cleaning up of my own code to get too. Cheers!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: