What is SPARK?
TODO. Read author’s paper here.
In a couple of words: a tool (a Python module), which allows to generate a «code» from a «source file», in four steps and three lines of Python code:
f = open(filename) generate(semantic(parse(scan(f)))) f.close() |
The task
Lets” suppose i want to automate configuring my shaper (Linux, HTB) in some way. So, i need to «invent» a syntax, then parse my configuration file, then check and generate «a code» (script for initializing a shaper).
Is it a «real world task»? I believe, yes: one can configure her shaper in any way (with GUI, storing configuration in SQL database, let’s say), but with SPARK it can be a tool for validating configuration. Surely, you will use rules and triggers with SQL database, other instruments with other tools, but all these ways may lead to SPARK. I mean, it’s easy to read a configuration from SQL and write in a text file, and then process it. Validate configuraion and generate a code (shell script in our case).
And, of course, i have simplified a syntax a bit. Anyway i will try it for the sake of demonstration ;-)
Syntax
We wil start with this syntax of configuration file:
# коментарі будемо іґнорувати. class 1:5 root { rate = 10240 descr = Root_as_root ceil = 20480 } class 1:50 parent 1:5 { ceil = 2048 rate = 1024 descr = My_favorite_client } class 1:53 parent 1:50 { descr = My_other_client ceil = 2048 rate = 1024 } |
Is it good or is it bad?
At this point we can not answer :-)
It is good if it allows to define configuration for our task; and now it is much more important to define a syntax for our «little language».
After some experiments i decided to choose this one:
classes ::= rootdef classdefs (1) rootdef ::= rootclass { params } (2) classdefs ::= classdef (3) classdefs ::= classdefs classdef classdef ::= ordclass { params } (4) params ::= ratedef params ::= ceildef params ::= descrdef params ::= params params ratedef ::= rate = number ceildef ::= ceil = number descrdef ::= descr = string rootclass ::= class classid root ordclass ::= class classid parent classid |
This means:
- Our classes shoud consist of root class definition and all another, «ordinary» classes,
- Root class definition should consist of «
rootclass
» definition and a set of parameters, - «All other classes» definition should be one or more «
classdef
» definitions… - which is, in turn, «
classdef
» and parameters… … and so on.
And we will try to build AST as follows:
classes /\ / \ / \ / \ / \ root classdefs /\ / \ / \ / \ / \ classdefs classdef . . . classdefs /\ / \ / \ / \ / \ classdefs classdef | | | classdef
You can see that out Syntax Tree does not reflect our syntax, to be honest. It misses «params
«, «ratedef
» nodes etc. But we omit them intentionally: with SPARK it’s easy to build AST «as you wish», to omit some nodes and to «inject» some others. And it’s a question of style, probably, which nodes will form AST for your task.
(And, probably, i choose nodes for tree not optimally. But let tree will be as shown, for demonstration’s sake, again.)
But this will follow; now go forward to Scanning.