Janet Production
What Is a Janet Production?
Most production types of the PDGL are written in C and compiled into machine code. Meaning that for most productions the scope of functionality is fixed at compile time. It's easy to see that fixing the functional scope at compile time limits the flexibility of the PDGL. A Janet production helps mitigate this issue by allowing the execution of arbitrary functionality during the resolution and termination of a production. Janet is a small Lisp style scripting language with an interpreter embeddable into other programs. The embedded Janet interpreter is fully featured and is what allows the incision of arbitrary functionality into a PDGL language specification.
Using a Janet Production
The Janet production takes in a script as the production output generator and then runs that script in a Janet interpreter. The standard Janet print function is used to pass replacement data back to the PDGL. This means calling:
will place the string value into the replacement string buffer.
Important
The Janet scripts do not maintain state between executions within the PDGL. That means if you want to maintain/pass state in a Janet script you must do it yourself.
One easy way to do this on a PC is by creating files. Here's an example from the linked site:
# opens a file named filename for writing, and writes Hello World!
(def f (file/open "filename" :w))
(file/write f "Hello World!")
(file/flush f)
(file/close f)
For the browser while I haven't looked into it, I suspect something similar can be done with the Emscripten file I/O system.
Warning!
In line with the PDGL portability and memory goals the output buffer for a Janet production is a fixed size of length DEFS_PDGL_MAX_STRING_SIZE.
Configuring
A Janet production contains two configurable scripts, the replacement script and the terminal script. The two scripts use the same execution flow but do not run in the same interpreter instance.
Examples
File I/O
[[production]]
name = "entry"
type = "pure"
replacements = ["%{janet prod}"]
terminals = [""]
[[production]]
name = "janet prod"
type = "janet"
replacement = '''#replacement script
(def f (file/open "filename" :w))
(file/write f "Hello World!")
(file/flush f)
(file/close f)
(print "terminal")
'''
terminal = '''#terminal script
(print "terminal")
'''
Use Library
[[production]]
name = "entry"
type = "pure"
replacements = ["%{janet prod}"]
terminals = [""]
[[production]]
name = "janet prod"
type = "janet"
replacement = '''#replacement script
(def number (math/random))
(print (string
number
)
)
'''
terminal = '''#terminal script
(print "terminal")
'''
Include Library
[[production]]
name = "entry"
type = "pure"
replacements = ["%{janet prod}"]
terminals = [""]
[[production]]
name = "janet prod"
type = "janet"
replacement = '''#replacement script
(import ./docs/manual/productions/janet/media/3/script :as scr)
(scr/dothething)
'''
terminal = '''#terminal script
(print "terminal")
'''
Supported by ./docs/manual/productions/janet/media/3/script.janet
Janet Entry
[[production]]
name = "entry"
type = "pure"
replacements = ["%{janet prod}"]
terminals = [""]
[[production]]
name = "janet prod"
type = "janet"
replacement = '''#replacement script
(def number (math/random))
(print (string
number
)
)
'''
terminal = '''#terminal script
(print "terminal")
'''
Production Schema
{
"$id": "janet-production_schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"type": {
"type": "string",
"const": "janet"
},
"replacement": {
"type": "string",
"minLength": 0,
"maxLength": 3000
},
"terminal": {
"type": "string",
"minLength": 0,
"maxLength": 3000
}
},
"additionalProperties": false,
"minProperties": 4
}