Skip to content

Commit

Permalink
Add describe support for device selectors
Browse files Browse the repository at this point in the history
Improve on our existing $__device support.

Next step: changing every single Thingpedia device to support this...
  • Loading branch information
gcampax committed Nov 1, 2019
1 parent a9cb280 commit a7ffe83
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 8 deletions.
26 changes: 26 additions & 0 deletions lib/ast/class_def.js
Expand Up @@ -23,6 +23,28 @@ const toJS = require('./toJS');

// Class definitions

function cleanKind(kind) {
// thingengine.phone -> phone
if (kind.startsWith('org.thingpedia.builtin.thingengine.'))
kind = kind.substr('org.thingpedia.builtin.thingengine.'.length);
// org.thingpedia.builtin.omlet -> omlet
if (kind.startsWith('org.thingpedia.builtin.'))
kind = kind.substr('org.thingpedia.builtin.'.length);
// org.thingpedia.weather -> weather
if (kind.startsWith('org.thingpedia.'))
kind = kind.substr('org.thingpedia.'.length);
// com.xkcd -> xkcd
if (kind.startsWith('com.'))
kind = kind.substr('com.'.length);
if (kind.startsWith('gov.'))
kind = kind.substr('gov.'.length);
if (kind.startsWith('org.'))
kind = kind.substr('org.'.length);
if (kind.startsWith('uk.co.'))
kind = kind.substr('uk.co.'.length);
return clean(kind);
}

/**
* The definition of a ThingTalk class.
*
Expand Down Expand Up @@ -60,6 +82,10 @@ class ClassDef extends Statement {
this.is_abstract = is_abstract || false;
}

get canonical() {
return this.metadata.canonical || cleanKind(this.kind);
}

*iterateSlots() {}
*iteratePrimitives() {}

Expand Down
28 changes: 26 additions & 2 deletions lib/describe.js
Expand Up @@ -351,6 +351,14 @@ class Describer {
return recursiveHelper(expr);
}

_getDeviceAttribute(selector, name) {
for (let attr of selector.attributes) {
if (attr.name === name)
return this.describeArg(attr.value, {});
}
return undefined;
}

describePrimitive(obj, scope, extraInParams = []) {
if (obj.selector.isBuiltin) {
if (obj.channel === 'return')
Expand Down Expand Up @@ -378,10 +386,26 @@ class Describer {
throw TypeError('Invalid @remote channel ' + channel);
} else {
confirm = schema.confirmation;

let cleanKind = obj.schema.class ? obj.schema.class.canonical : clean(obj.selector.kind);

let selector;
let name = this._getDeviceAttribute(obj.selector, 'name');
if (obj.selector.device)
confirm = confirm.replace('$__device', obj.selector.device.name);
selector = this._("your %s").format(obj.selector.device.name);
else if (obj.selector.all && name)
selector = this._("all your %s %s").format(name, cleanKind);
else if (obj.selector.all)
selector = this._("all your %s").format(cleanKind);
else if (name)
selector = this._("your %s %s").format(name, cleanKind);
else
confirm = confirm.replace('$__device', clean(kind));
selector = this._("your %s").format(cleanKind);

if (confirm.indexOf('$__device') >= 0)
confirm = confirm.replace('$__device', selector);
else if (confirm.indexOf('${__device}') >= 0)
confirm = confirm.replace('${__device}', selector);
}

let firstExtra = true;
Expand Down
3 changes: 2 additions & 1 deletion lib/grammar.pegjs
Expand Up @@ -303,7 +303,8 @@ device_selector = type:class_name _ attrlist:input_param_list {
all = value.toJS();
}
}
return new Ast.Selector.Device(type, id, null, attrlist.filter((attr) => attr.name !== 'id'), !!all);
return new Ast.Selector.Device(type, id, null,
attrlist.filter((attr) => attr.name !== 'id' && attr.name !== 'all'), !!all);
}
device_attribute_list = first:device_attribute _ rest:(',' _ device_attribute _)* {
return [first].concat(take(rest, 2));
Expand Down
14 changes: 14 additions & 0 deletions test/test_describe.js
Expand Up @@ -303,6 +303,20 @@ var TEST_CASES = [
`tweet ____ every day at ____`, 'Twitter'],
[`now => @com.twitter.post(status = $context.selection : String);`,
`tweet the selection on the screen`, `Twitter`],

['now => @light-bulb.set_power();',
'turn ____ your light-bulb', 'Light Bulb'],
['now => @light-bulb(name="bedroom").set_power();',
'turn ____ your “bedroom” light-bulb', 'Light Bulb'],
['now => @light-bulb(name="bedroom", all=true).set_power();',
'turn ____ all your “bedroom” light-bulb', 'Light Bulb'],
['now => @light-bulb(all=true).set_power();',
'turn ____ all your light-bulb', 'Light Bulb'],

[`monitor (@smoke-alarm.status()) => notify;`,
'notify you when the status of your smoke alarm changes', 'Smoke Alarm ⇒ Notification'],
[`monitor (@smoke-alarm(name="kitchen").status()) => notify;`,
'notify you when the status of your “kitchen” smoke alarm changes', 'Smoke Alarm ⇒ Notification'],
];

const gettext = {
Expand Down
12 changes: 7 additions & 5 deletions test/thingpedia.tt
Expand Up @@ -708,19 +708,18 @@ class @org.thingpedia.builtin.thingengine.builtin
#_[canonical="say"]
#_[confirmation="send me a message $message"];
}
class @light-bulb
#_[canonical="light bulb"] {
class @light-bulb {
action alert_long()
#_[canonical="flash alert lights on light bulb"]
#_[confirmation="flash alerts on your lightbulb"];
#_[confirmation="flash alerts on ${__device}"];

action color_loop()
#_[canonical="color loop lights on light bulb"]
#_[confirmation="loop colors on your lightbulb"];
#_[confirmation="loop colors on ${__device}"];

action set_power(in req power: Enum(on,off) #_[prompt="Do you want to turn it on or off?"] #_[canonical="power"])
#_[canonical="set power on light bulb"]
#_[confirmation="turn $power your lightbulb"];
#_[confirmation="turn $power ${__device}"];
}
class @com.hue
#_[canonical="philips hue"] {
Expand Down Expand Up @@ -767,6 +766,9 @@ class @com.gmail
}
class @smoke-alarm
#_[canonical="smoke alarm"] {
monitorable query status(out detected : Boolean)
#_[canonical="smoke alarm status"]
#_[confirmation="the status of ${__device}"];
}
class @com.google.drive
#_[canonical="google drive"] {
Expand Down

0 comments on commit a7ffe83

Please sign in to comment.