Skip to content

Commit

Permalink
Add NN syntax for device selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
gcampax committed Nov 1, 2019
1 parent 3aa9bd6 commit 7b5037e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
4 changes: 4 additions & 0 deletions lib/nn-syntax/lexer.js
Expand Up @@ -100,6 +100,10 @@ module.exports = class SequenceLexer {
let [,paramname,] = next.split(':');
this._lastparam = paramname;
next = new TokenWrapper('PARAM_NAME', paramname);
} else if (next.startsWith('attribute:')) {
let [,paramname,] = next.split(':');
this._lastparam = paramname;
next = new TokenWrapper('ATTRIBUTE_NAME', paramname);
} else if (next.startsWith('unit:')) {
next = new TokenWrapper('UNIT', next.substring('unit:'.length));
} else if (next.startsWith('device:')) {
Expand Down
24 changes: 23 additions & 1 deletion lib/nn-syntax/parser.lr
Expand Up @@ -238,8 +238,30 @@ action = {
call => new Ast.Action.Invocation(call, null);
}
selector = {
fn:FUNCTION => [new Ast.Selector.Device(fn.value.kind, null, null), fn.value.channel];
selector attr:device_attribute => {
const [sel, chan] = selector;
if (attr.name === 'id')
sel.id = attr.value.toJS();
else if (attr.name === 'all')
sel.all = attr.value.toJS();
else
sel.attributes.push(attr);
return selector;
};
}
device_attribute = {
pname:ATTRIBUTE_NAME '=' v:constant => new Ast.InputParam(pname.value, v);
}
call = {
fn:FUNCTION => new Ast.Invocation(new Ast.Selector.Device(fn.value.kind, null, null), fn.value.channel, [], null);
selector => {
const [sel, chan] = selector;
return new Ast.Invocation(sel, chan, [], null);
};
inv:call ip:const_param => {
inv = inv.clone();
inv.in_params.push(ip);
Expand Down
42 changes: 24 additions & 18 deletions lib/nn-syntax/tonn_converter.js
Expand Up @@ -702,6 +702,28 @@ module.exports = class ToNNConverter {
}
}

_invocationToNN(invocation) {
let fn = `@${invocation.selector.kind}.${invocation.channel}`;
if (invocation.selector.all)
fn = List.concat(fn, 'attribute:all:Boolean', '=', 'true');
invocation.selector.attributes.sort((p1, p2) => {
if (p1.name < p2.name)
return -1;
if (p1.name > p2.name)
return 1;
return 0;
});
for (let attr of invocation.selector.attributes) {
if (attr.value.isUndefined && attr.value.local)
continue;

// explicitly pass null to valueToNN because there should be no parameter passing in NN-syntax
fn = List.concat(fn, `attribute:${attr.name}:String`, '=', this.valueToNN(attr.value, null));
}

return fn;
}

tableToNN(table) {
if (table.isVarRef) {
throw new UnsynthesizableError('Table macros');
Expand All @@ -711,10 +733,6 @@ module.exports = class ToNNConverter {
else
return List.concat(`result`, '(', `@${table.kind}.${table.channel}`, '[', this.valueToNN(table.index, null), ']', ')');
} else if (table.isInvocation) {
let principal = null;
if (table.invocation.selector.principal !== null)
principal = this.valueToNN(table.invocation.selector.principal, null);

let params = List.Nil;
table.invocation.in_params.sort((p1, p2) => {
if (p1.name < p2.name)
Expand All @@ -733,11 +751,7 @@ module.exports = class ToNNConverter {
params = List.concat(params, `param:${inParam.name}:${ptype}`, '=', this.valueToNN(inParam.value, null));
}

let fn = `@${table.invocation.selector.kind}.${table.invocation.channel}`;
if (principal)
return List.concat(fn, 'of', principal, params);
else
return List.concat(fn, params);
return List.concat(this._invocationToNN(table.invocation), params);
} else if (table.isFilter) {
let optimized = filterToCNF(table.filter);
if (optimized.isFalse)
Expand Down Expand Up @@ -820,10 +834,6 @@ module.exports = class ToNNConverter {
}

actionInvocationToNN(action, outschema) {
let principal = null;
if (action.selector.principal !== null)
principal = this.valueToNN(action.selector.principal, null);

let const_param = List.Nil;
let param_passing = List.Nil;

Expand All @@ -848,11 +858,7 @@ module.exports = class ToNNConverter {
}
}

const fn = `@${action.selector.kind}.${action.channel}`;
if (principal)
return List.concat(fn, 'of', principal, const_param, param_passing);
else
return List.concat(fn, const_param, param_passing);
return List.concat(this._invocationToNN(action), const_param, param_passing);
}

actionToNN(action, outschema) {
Expand Down
4 changes: 4 additions & 0 deletions test/test_nn_syntax.js
Expand Up @@ -458,6 +458,10 @@ const TEST_CASES = [
[`compute distance ( param:location:Location , location:current_location ) of ( monitor ( @com.yelp.restaurants ) ) => notify`,
`get restaurants and their distance from here`, {},
`compute distance(location, $context.location.current_location) of (monitor (@com.yelp.restaurants())) => notify;`],

[`now => @light-bulb.set_power attribute:name:String = " bedroom " param:power:Enum(on,off) = enum:off`,
`turn off my bedroom lights`, {},
`now => @light-bulb(name="bedroom").set_power(power=enum(off));`],
];

async function testCase(test, i) {
Expand Down

0 comments on commit 7b5037e

Please sign in to comment.