|
Dap 0.1.5 Language Quick Tour
Dap syntax was developed with two main concerns:
- to be easily parsable
- to be concise, yet human-readable
Dap syntax is pretty much different from what web-developers are used to. It might seem complicated and cumbersome when reading syntax specification, but when it comes to actual coding — it turns out to be quite easy and handy.
I'd recommend that you see the 'Hello, world' tutorial before getting into dap syntax details. That would help you keep track of what is it all about.
Rules and Phases
All dap rules consist of steps, steps consist of tokens, tokens consist of parts. Very simple:
rule ::=step{; step}
step ::=token{ token}
token::=[field][$status][@alias{,alias}][:converter{,converter}][=value]
That is, steps within a rule are separated by semicolon+space; header and tokens within a step — by a single space; multiple aliases and converters are separated by commas. All token parts are grammatically optional. Empty strings are valid names, but in many cases they are reserved and have a special meaning.
A dap-enabled node may have none, any or both of the following rules, corresponding to node life phases:
-
Data or Down phase: d-rule
When a dap node is populated, its content is generated using its d-rule, according to data provided to it and current status of its scope. Execution of d-rule of a node may change its scope's status, and theese changes will be observable by the nodes's descendants.
-
User or Up phase: u-rule
When a dap node is activated (usually, by a user-related event), its own u-rule and u-rules of its ancestors are executed, starting from the node and bubbling up. Changes in node's scope status are automatically reflected in all dap-nodes observing that scope (dependent nodes). If a dependent node detects changes, which influence its content, it gets updated automatically to reflect those changes.
Steps and Tokens
Each rule consits of one or more steps, wich are executed consequently on the rule run. A step consists of tokens. The first token of a step is 'the head'; the rest are data tokens (or simply 'tokens'). Data tokens define data involved in the step execution; step head specifies actions to perform on that data.
Zero or more data tokens may participate in execution of each step. A token is a structure, that defines the datapiece passed to a mapper. Data tokens are not just identifiers, but execution units wich provide some simple data manipulations, such as data binding, assignments and conversions. Token may reference a field in a datarow received from a data source, or a node's scope status variable or specify a literal value. Token also specifies converters for the datapiece, and aliases, under wich the datapiece is fed to the mapper.
Each token may contain:
- datafield reference
- status variable reference
- aliases
- converters
- literal value
Token parts are separated by their respective prefixes: $ (dollar sign) — for a status variable name, @ (at sign) — for alias chain, : (colon) — for conversion chain, = (equal sign) — for value. Datafield name, if present, is not prefixed, but is placed as first part of a token. All token parts are optional, but their order is mandatory. Full token looks like:
datafield$status@aliasOne,aliasTwo:converter1,converterN=value
and its meaning is:
- read value from the node's associated datarow's datafield or take literal value if datafield is omitted or not provided in the datarow.
- store it in a status variable,
- sequentially apply all the converters,
- tag the executed token as aliasOne,aliasTwo.
Omitting any token parts modifies token behavior in a straightforward manner:
- if no converts specified, data is fed as is
- if neither datafield nor literal value specified, the status variable's own value is taken
- if no status variable specified, none is changed
- if no alias provided, the result is named after the status variable or the datafield (or named with empty name, if none of those are specified).
Status variables as sources and as targets
As can be seen from the token structure description above, a status variable's value can be set (by specifying a literal value or a datafield) and can be read (by omitting literal value and datafield).
Setting a status variable's value has different semantics for up and down phases:
-
at the down-phase, a new status variable is created in current scope; should a one with the same name already exist in outer scope, it is hid from the current scope (yet remains visible for other scopes)
-
at the up-phase, the addressed status variable is first searched in outer scope, then, if not found, created new.
Reading a variable always assumes that it has already been defined for the scope, otherwise rule fails.
Converters
Converters allow to transform the result of token execution. IMPORTANT: converters only change the result, not the source of value. This changed value is fed to flattener or mapper, but not written back to the variable or datafield it was obtained from.
Dap core provides the following converters:
-
esc , usc
escape/unescape(string)
-
+ , -
absolute/negate value(number)
-
? , !
test if value(any type) present/missing
-
+? , -? , 0?
test if value(number) is positive/negative/zero
-
#get , #cfg , #dat , #lib
converters of this group "convert" the value(url) into data received from that url
-
csv
"Comma-separated values". Converts x1,x2,x3-like string into a single-column rowset.
-
nvp
"Name-value pairs". Converts x1:y1;xN:yN-like string into a multi-column (x,y) rowset. Rows need not be "pairs", any number of colon-separated columns is allowed.
Custom converters may be defined in extension libraries.
Step head
Step head is the first token of a step. Step head itself doesn't fetch datapieces; it defines what to do with the rest of the token list. It has the same grammatical structure as an ordinary token, except that its datafield specifies a dap mapper, and its value specifies a token list flattener.
Flatteners
A flattener may be applied to the token list to convert the whole list into a single datum, wich is fed to the mapper instead of individual tokens of the step. Aliases for the flattened datum are specified in the step head's @aliases part.
The most basic dap core flatteners are:
-
concat
Concatenates values of all tokens into a single string
-
space
Concatenates values by a single space
-
url
Builds an URLEncoded query string. Anonymous tokens are appended unencoded.
-
? , !
ANY(returns first non-empty value from the token list) / LACK (returns true if at least one token is false/empty)
In conjunction with ! , these converters become NONE / ALL respectively
-
eq , asc , dsc
Check respectively for: equality, monotonous ascend or monotonous descend of the token list Equality check may be performed upon both numbers and strings, ascend and descend — only upon numbers.
-
Examples
!=concat =abra @foo=cada @bar=bra abracadabra
!=space =abra @foo=cada @bar=bra abra cada bra
!=url =abra @foo=cada @bar=bra =hmaputra abra&foo=cada&bar=brahmaputra
!=? @empty= @foo=cada @bar=bra cada
?=eq =abra @foo=cad @bar=abra false
?=eq =abra @bar=abra true
?=asc =-1 =7 =12 =13 true
?=asc =-1 =7 =15 =13 false
?=dsc =-1 =-7 =-12 =-13 true
Custom flatteners can be defined in external libraries.
Mappers
Mappers to dap are what functions for javascript are. They take arguments and perform actions. Since version 0.1.5, all dap mappers are unary — they deal with only one token at a time. Multiple tokens in a step are executed as a 'for each token' sequence.
Since all mappers are unary, the following signature is used for their description:
mapper @aliases=value
Each token comes to a mapper as an @alias1,aliasN=value datapiece. Aliases are specified by token's @aliases part (may be a single alias, or multiple aliases comma-separated), and value is the result of token execution — a datafield value, a variable value, or a literal; the value is also subject to conversions, if specified. If the token's alias is empty (like =value , or datafield@ , or datafield$status@:convert=value , etc.), the token is said 'anonymous'.
The basic dap core mappers are:
-
(empty)
Empty mapper does nothing. The pure effect of such a step is execution of its token list.
Examples
d=" $foo=0 $bar="
defines new variables: $foo initiated with 0, and empty $bar
d=" price$"
defines a new variable $price , and initiates it from a datafield price
d=" wholesale$price=0 discount$=0"
defines two variables: $price and $discount . The $price is initiated from the wholesale datafield or 0 if wholesale not provided in the datarow. The $discount is initiated from datafield discount , or 0 if it is not provided.
d=" $user $shop"
marks the node as dependent from $user and $shop , forcing it to update when any of $user or $shop change
u=" item$ price$"
on up-phase, variables $item and $price are updated from respective datafields
-
! @aliases=value
Writes the value to the output node. Aliases are ignored.
Examples
d="! $prefix root $suffix"
writes $prefix , root , $suffix one by one, all as separate text nodes, though they will usually look concatenated in viewport
d="!=concat $prefix root $suffix"
writes a single text node, containing a concatenation of $prefix , root , $suffix .
d="!=space firstname lastname"
writes a text node, as firstname and lastname concatenated by space
d="! myTemplates.hello firstname"
writes the hello template from myTemplates library and the firstname datafield.
-
? @aliases=value
Conditional gate: allow execution of the rest of the rule only if value matches one of the aliases (for anonymous tokens, if value is true/non-empty); otherwise, rule terminates.
Examples
d="? $page@catalog,basket"
allows further execution of the rule if $page 's value is whether 'catalog' or 'basket'
d="?=? $public@ name@ login@ email@"
allows if $public is true, or any of name , login , email datafields are not empty. (The 'any' aggregation is performed by the ? flattener)
d="? $foo@"
allows if $foo is true/non-empty
d="? $foo@:!"
allows if $foo is false/empty (the ! convertor turns false to true and vice versa)
-
attr @aliases=value
Sets all attributes specified in aliases to given value.
Examples
d="attr @id,name=myNode"
adds id and name attributes to the node, both set to 'myNode'
d="attr@src=url =/images/ $imageId@ =.jpg"
adds src attribute set to the calculated URL
-
ui @aliases=value
UI element. Assigns event listeners specified in aliases, with a handler specified by value (or default, if value is false/empty) to the node. Has a reduced form — tokenless — to assign click event listener and default handler.
Examples
d="ui"
adds 'click' event listener with default handler (launch u-phase on click)
d="ui@change,blur"
adds 'change' and 'blur' events listeners with the default handler
d="ui @mouseover=myOwnHandler @dblclick="
hangs myOwnHandler on the node's 'mouseover' event, and default handler on 'dblclick' event
-
* @aliases=value
Populates a rowset: executes the rest of the rule for each row in the value (rowset). If the token is fed anonymous, datafield names are as provided in the rowset; if aliases provided, datafields are respectively (re)named.
Examples
d="* @color,hex:nvp=red:F00;green:0F0;blue:00F"
populates a rowset of primary RGB colors, each row containing color and hex datafields
d=" $colors=yellow:FF0;cyan:0FF;magenta:F0F; * $colors@color,hex"
populates a rowset of complementary RGB colors from a variable
d="* :#dat=/myData.asp"
populates a rowset from a dataset, wich is, in turn, loaded from /myData.asp
d="*:#dat=url =/myData.asp? @style=verbose"
populates a rowset from /myData.asp?&style=verbose
Field-modifying mappers
Field-modifying mappers are used to modify a target' s fields. The target may be a status variable, or the node's datarow.
-
%$target @aliases=value
Adds new (or updates existing) fields specified by aliases into the target.
Examples
d="%@grossweight=+ peas water can"
creates a datafield as sum (the + flattener) of other datafields.
u="%$person@fullname=space firstname lastname"
adds to the $person variable a new field — fullname , combined from the firstname and lastname datafields
-
~$target @aliases=value
Copies fields specified by aliases from value into target.
Examples
d="~ @surname,fullname:csv,usc=Bond,James%20Bond"
adds the two datafields (surname ,fullname ) to node's datarow
u="~$address @city,street,building:csv=Moscow,Red-Square,1 @zip,country:csv=123456,RUSSIA;
! $address.city $address.country"
Target $address will contain the five fields; they can be accessed by dot notation.
-
-$target @aliases=value
Toggles the target's fields specified by aliases. If a particular field is empty it is set to value (or true, if value not provided), otherwise set to empty.
Examples
d="-$expand"
toggles the value of $expand
d="- @name,email,phone=missing"
sets the datafields (name , email , phone ) having empty value, or not provided in the datarow, to 'missing'
u="-$contact @name,email,phone=missing"
sets the unprovided fields of $contact to 'missing'
-
+$target @aliases=value
Confirms the target's fields specified by aliases. If a particular field is not empty it is set to value (or true, if value not provided), otherwise remains empty.
Examples
d="+ @name,email,phone=present"
sets the datafields (name , email , phone ) having non-empty value, to 'present'
u="+$contact @name,email,phone=present"
sets non-empty fields of $contact to 'present'
Custom mappers can be defined in external libraries.
See also:
|