reka.js
reka.js copied to clipboard
Resolving variable ambiguity
Overview
Currently, Reka resolve variables by their names and scope:
{
type: "Program",
globals: [ { type: "Val", name: "counter", ... }
components: [
{
type: "RekaComponent",
name: "App",
state: [ { type: "Val", name: "counter", ... }
template: {
type: "TagTemplate",
tag: "text",
props: {
"value": {
type: "Identifier",
name: "counter" // refers to the state variable
}
},
}
}
]
}
In the above example, the counter
variable used as prop refers the counter state variable in the App component, rather than the global variable. This design is simple and straightforward and it's based on what programmers typically expect when writing code.
However, this does make referencing the global counter
variable impossible. More importantly, when building a page editor — the names of these variables are going to be defined by users and chances are we’re going to need to build some user friendly UI (ie: a dropdown to list variables). In which case, having variables to be resolved by names and scopes is going to cause a lot of confusion.
Removing ambiguity in the State
To solve this, we need a more explicit way to resolve variables. We can achieve this by requiring identifiers to specify the id of the variable explicitly:
{
type: "Program",
globals: [ { id: "hhghak1", type: "Val", name: "counter", ... }
components: [
{
type: "RekaComponent",
name: "App",
state: [ { id: "kbamk10", type: "Val", name: "counter", ... }
template: {
type: "TagTemplate",
tag: "text",
props: {
"value": {
type: "Identifier",
ref: "hhghak1" // refers to the global variable
}
},
}
}
]
}
Parser
To support this change, we will need to make some changes to the Parser as well. An easy way to achieve a non-ambiguous to require identifiers to specify the “path” of the variable they are referencing:
val counter = 0;
component App() {
val counter = 1;
} => (
<text value={$state.counter} />
)
Here, $state.counter
explicitly specifies that we’re referencing the state variable. Similarly we can allow the following:
-
$counter
to reference a globalcounter
variable -
$prop.counter
to reference a propcounter
variable
One other place where we need to take care of this is in templates with the @each
directive. Currently consumers can create a variable to reference each item in the iterator:
<div @each={item in [1,2,3]}>
<div @each={item in [1,2,3]}>
<text value={item} /> // item refers to the nested item
</div>
</div>
In this case, it is also impossible to reference the outer iterators item
using our existing model. Using the same solution with the counter
example, we can do the following:
<div @each={item in [1,2,3]}>
<div @each={item in [1,2,3]}>
<text value={$each.0.item} /> // item refers to the outer item
</div>
</div>