| 1 | [[PageOutline]] |
| 2 | |
| 3 | = Using variables in semantic queries = |
| 4 | While writing semantic queries sometimes we need to refer back to a property of an entity at some earlier point. To make it clear suppose we want to write such query. A query always has the starting point {{{mods}}}. Moving on we select functions with {{{funs}}}. Here we need to filter all the functions based on its module. Here come the variables in. |
| 5 | |
| 6 | The problem can easily solved by the following query: |
| 7 | {{{ |
| 8 | mods[name=A].funs[name==A] |
| 9 | }}} |
| 10 | |
| 11 | Here for each module the variable {{{A}}} binds the module's name, that is, the value of {{{A}}} changes. |
| 12 | |
| 13 | In the following sections we show how to make variable bindings and present some examples of using variables in semantic queries. |
| 14 | |
| 15 | == Binding == |
| 16 | Variables can only be created using properties in filters. It is ''valid'' to write |
| 17 | {{{ |
| 18 | mods[name=A] |
| 19 | }}} |
| 20 | or |
| 21 | {{{ |
| 22 | mods.funs[A=arity] |
| 23 | }}} |
| 24 | |
| 25 | but it is ''semantic error'' to write |
| 26 | {{{ |
| 27 | mods[A=not_a_property] |
| 28 | }}} |
| 29 | or |
| 30 | {{{ |
| 31 | mods[A=2].funs[arity==A] |
| 32 | }}} |
| 33 | |
| 34 | As you may noticed, the binding operator {{{ = }}} is commutative. Also, one may interchangeably use {{{ = }}} and {{{ == }}} to bind and compare. The first {{{ = }}} or {{{ == }}} binds, the others compare. |
| 35 | |
| 36 | The general form of binding is the following: |
| 37 | {{{ |
| 38 | [property=Variable] |
| 39 | }}} |
| 40 | or |
| 41 | {{{ |
| 42 | [Variable=property] |
| 43 | }}} |
| 44 | |
| 45 | Variables may bind to values of any type. They can hold atoms, integers, strings etc. |
| 46 | |
| 47 | == Occurences == |
| 48 | |
| 49 | === Filters === |
| 50 | Variables can only occur in filters. In its simplest form a semantic query is sequence of selectors and filters. When a variable binding takes place the variable can be used in any following filter. In other words, the ''scope'' of a variable is right from its binding. |
| 51 | {{{ |
| 52 | mods.funs[name=A].calls[name==A] |
| 53 | }}} |
| 54 | yields all function that called by a function with the same name. Example output would be: |
| 55 | {{{ |
| 56 | module_a:f/0 |
| 57 | module_b:f/1 |
| 58 | module_b:g/2 |
| 59 | module_c:g/1 |
| 60 | }}} |
| 61 | means in the program code {{{f/0}}} calls {{{f/1}}}. |
| 62 | |
| 63 | In comparisons it is allowed to use every operator that standard semantic query language allows. This means {{{==, /=, >, >=, <, <=}}} and {{{ ~ }}}. A variable can be compared to property, variable and literal. |
| 64 | |
| 65 | {{{ |
| 66 | mods.funs[arity=A, A>2] |
| 67 | mods.funs[exported=A, dirty/=A, A==true] |
| 68 | mods[name=A].funs[name=B, A==B] |
| 69 | }}} |
| 70 | |
| 71 | ==== Conversion ==== |
| 72 | It is important to note that any form of ''conversion'' between types is ''not supported''. When you use a value of a variable in a comparison, you have to make sure that both operands have the same type. |
| 73 | {{{ |
| 74 | mods.funs[name=A].vars[name==A] |
| 75 | }}} |
| 76 | yields type error, because {{{vars.name}}} has type of string. |
| 77 | |
| 78 | |
| 79 | === Iterations === |
| 80 | Writing such query as |
| 81 | {{{ |
| 82 | mods.funs.{calls[name=A]}2.name |
| 83 | }}} |
| 84 | is exactly the same as writing |
| 85 | {{{ |
| 86 | mods.funs.calls[name=A].calls[name=A].name |
| 87 | }}} |
| 88 | |
| 89 | It sheds light on that binding always happens in the first iteration. |
| 90 | |
| 91 | One may use previously bound variable or use variable bound inside the iteration later: |
| 92 | {{{ |
| 93 | mods.funs[name=A].{calls[name==A]}3 |
| 94 | mods.funs.{calls[name=A]}2.mod[name==A] |
| 95 | }}} |
| 96 | |
| 97 | === Closures === |
| 98 | Similarly to iterations, variables can be used in transitive closures. Here are some examples: |
| 99 | {{{ |
| 100 | mods.funs.(calls[name=A)+ |
| 101 | mods.funs[name=A].(calls[name=A])2.name |
| 102 | }}} |
| 103 | |
| 104 | The first means all possible call chains that consist of functions with the same name from the second chain link onwards. Example output would be: |
| 105 | {{{ |
| 106 | module_a:f/0 module_a:g/0 module_a:g/1 |
| 107 | module_a:g/0 module_a:g/1 |
| 108 | }}} |