nsensfel / tonkadur

Narrative scripting/programming tool. Write stories in your favorite editor using a feature-rich language, compile them into a very small and simple language to easily integrate them into your game.
https://tonkadur.of.tacticians.online
Apache License 2.0
2 stars 0 forks source link

Allow higher-order computations #2

Closed nsensfel closed 4 years ago

nsensfel commented 4 years ago

Allow handling of serialized computations in Fate and Wyrd:

nsensfel commented 4 years ago

This adds the risk for dependency cycles, though:

(set a_serial_var
  (serialize
     (eval a_serial_var)
  )
)

Since the value of these variables can change, detecting a cycle statically isn't going to be trivial. Two solutions:

I'd prefer going with the latter, and simply put a big warning in the doc.

nsensfel commented 4 years ago

After some reflection, this is now considered to be a candidate for an extension instead of being in the base language. The issue stems from any code being serialized needing its own program counter.

Serialization is only meant for computations, which, in Wyrd, do not require any program counter. However, the goal is to have it serialize Fate computations, and a lot of Fate computations are compiled into not only Wyrd computations, but also sequences of Wyrd instructions, which would need that specific program counter and would thus lead to additional complexity in adding Wyrd support to an existing engine.

I do not think serialized computations are going to be used often enough to warrant making support for the language more difficult to achieve. I'll just have them serve as the example of extension instead.

nsensfel commented 4 years ago

sequences of Wyrd instructions, which would need that specific program counter

I could store/restore the value of the program counter using the existing labels feature of the compiler, a dedicated int list, and set_pc. At this point, this is pretty much equivalent to adding feature-complete functions. The issue would then be anonymous variables (and the function parameters, since I might as well add these): I need one structure defined per function, a list of pointer for that struct per function, and a recursion count for each function. The struct should simply have a field for storing the pc, instead of the dedicated int list, and a field for any result.

nsensfel commented 4 years ago

Current idea: (lambda <t0 = BASE TYPE> ({type_list})) is a type corresponding to code that returns a value of type t0 and requires parameters of types {type_list}.

(lambda <t1 = BASE TYPE>
   ({typed_param_list})
   {instruction_list}
   (return <v>)
)

defines a value of type (lambda ...). (eval {reference} ({value_list})) executes the code at {reference}.

(local <t2 = TYPE> {n1 = String}) is a general instruction that declares a variable that only exists within the current context (and not even any context created within that context).

nsensfel commented 4 years ago

Actually, lambdas should only be computations in Fate: knowing when a Fate computation is performed in the resulting Wyrd code is very counter-intuitive. Functions could be implemented by having sequences take parameters. No return values, however, since that would also classify them as computations. Instead, pointer parameters should be used.

nsensfel commented 4 years ago

Implemented, as of https://github.com/nsensfel/tonkadur/commit/6655cdcd1c28ac36c8af144573c396d96b9dceee.