So, err, hi. I haven't yet made anything towards the opengl stuff I specsed in last post. I realized I have to be able to write actual shaders to be able to use them in-editor. Thus, I wrote a server for M-x find-file :ing and M-x save-buffer :ing, and then I made an emacs mode client. The script assets in the editor have a property called NS, which is kind-of like the IDs used internally by the editor to refer assets, but unlike IDs (which are supposed to look like they have been gensym'd), NS's are to be human readable. The emacs mode uses them to refer to script assets. NS's are a property of the asset, not of the language. Thus both GLSL and Scheme scripts both have an NS.
Assuming a scheme script in NS qmapper.demo and an editor running in localhost port 7777, you'd open it by first enabling qmapper-editor-mode and then trying to find file in path 'QM:localhost:7777:qmapper.demo'. It's a colon-separatd string, where the first part is kind-of a protocol specifier, then is the host, the next is port, and finally it's the NS. The current regex that splits this is specified here, and it's somewhat buggy. I have to fix it a bit at the latest when I'm going to create something with this editor
But, this is supposed to be a spec about the propertylisp. So, let's spec
A Spec
Propertylisp isn't a real lisp (as in, has a repl or anything else useful). It's an s-expression based macro-language which has a compiler that outputs C++ - classes with a basic runtime reflection. I might've been able to implement the same by using Qt's RTTI-hacks or something else, but I don't know how to use those. I know the result I want, and I know how to transform S-expressions to a more inferior syntax. So, propertylisp supports c++ classes with fields, functions and properties. As properties are not a native construct in c++, they are implemented as getProp(T val) and setProp(T val). There are also void set(std::string propname, T val) and T get(std::string propname) - methods for reflection use. Programmer may query general propertierbase (the class inherited by all output of the compiler) pointers of their actual type, their properties and the types of those properties. All fields, functions and props need privacy specifiers (public, protected, private). You may set up runtime validators on properties' values, by including a C function and using its name as a symbol. Validators will be called when setting the prop's value, and each of them must return true to let the prop's value be set. The validator has to conform to signature bool validatorFn(T val, const std::function<void(std::string)> &error_reporter), where T is property's type.
Let's see an example, here's a definition of a script-asset:
(defcppclass
;; Classe's name
Script
;; Headers the final class needs
("<string>" "<script-types.h>" "<nsValidators.h>")
(public
(properties
(std__string contents "")
(std__string name "")
(std__string ns "user"
;; The validator functions, this is specified in the nsValidators.h
(doesntContainNs))
(scriptTypes script_type scheme))))
Comments are supposed to explain everything :D
Here's another example:
(defcppclass root ("<propertierbase.h>" "<map>" "<string>" "<boost/flyweight.hpp>" "<QString>" "<either.h>") ;; These will be macro-expanded this way: ;; class root; class Layer; (declare-class "Map" "Layer") (public (fields ;; __ will be expanded as :: ;; ___ will be expanded as ', ' because space isn't valid in a lisp symbol (std__map<flyweight<std__string>___Propertierbase*>* registry nullptr)) (functions (flyweight<std__string> indexOf (int row)) (int rowOf (flyweight<std__string> id)) (either<scriptTypes___std__string> findNs (std__string ns)) (void saveNs (std__string ns std__string content)) (bool containsNs (std__string ns)))))
If you ever need to develop qmapper, there's a shell script that runs the propertylisp compiler server every time a file in $input directory is touched. There's also a shell script that cleans the output if needed.