Skip to content

Instantly share code, notes, and snippets.

@benbenbenbenbenben
Created December 17, 2015 10:42
Show Gist options
  • Save benbenbenbenbenben/1afb4c94eafc058bdc3e to your computer and use it in GitHub Desktop.
Save benbenbenbenbenben/1afb4c94eafc058bdc3e to your computer and use it in GitHub Desktop.
%{
Date.prototype.get_floor = function() {
return this.low_resolution
? new Date(this.getYear() + 1900, this.getMonth(), this.getDate())
: this;
}
Date.prototype.get_ceiling = function() {
return this.low_resolution
? new Date(this.getYear() + 1900, this.getMonth(), this.getDate(), 23, 59, 59, 999)
: this;
}
Date.prototype.set_low_resolution = function(en) {
this.low_resolution = en;
}
function safeparse(k) {
var parts = /(\d+)\/(\d+)\/?(\d*)(\s+)?(\d+)?\:?(\d+)?\:?(\d+)?\.?(\d+)?/.exec(k);
var dd = parseInt(parts[1]),
mm = parseInt(parts[2]),
yy = parseInt(parts[3]),
h = parseInt(parts[5]),
m = parseInt(parts[6]),
s = parseInt(parts[7]),
ms = parseInt(parts[8]);
/* caution: deliberate millennium bug */
yy = yy < 100 ? 2000 + yy : yy;
var date = new Date(yy || new Date().getYear() + 1900, mm - 1, dd, h || 0, m || 0, s || 0, ms || 0);
if (isNaN(h))
date.set_low_resolution(true);
return date;
}
%}
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+ return 'INTEGER'
[0-9]+("."[0-9]+)?\b return 'REAL'
'to' return 'TO'
'from' return 'FROM'
':' return ':'
'/' return '/'
'>=' return 'GTE'
'<=' return 'LTE'
'>' return 'GT'
'<' return 'LT'
',' return 'COMMA'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%left '>' '<' '>=' '<='
%start query
%% /* language grammar */
query
: statements EOF
{ var statements = Array.prototype.concat($statements);
var program = function(k) {
var result = false;
while(result == false && statements.length > 0)
result = result | statements.shift()(k);
return result;
}
return program;
}
;
time
: INTEGER ':' INTEGER ':' REAL
{$$ = $1 + ':' + $3 + ':' + $5;}
| INTEGER ':' INTEGER
{$$ = $1 + ':' + $3 + ':00';}
;
date
: INTEGER '/' INTEGER '/' INTEGER
{$$ = $3 + '/' + $1 + '/' + $5;}
| INTEGER '/' INTEGER
{$$ = $3 + '/' + $1 + '/' + (1900 + (new Date().getYear())).toString();}
;
op
: GT
| LT
| GTE
| LTE
| TO
| FROM
;
datetime
: date time
{$$ = new Date($date + ' ' + $time);}
| date
{$$ = new Date($date); $$.set_low_resolution(true);}
| time
{$$ = new Date(new Date().date() + $time);}
;
statements
: statement
| statement COMMA statements
{$$ = Array.prototype.concat($statement, $statements);}
;
statement
: datetime
{$$ = function(k) {
k = safeparse(k);
if ($datetime.low_resolution) {
k.set_low_resolution(true);
}
return k.get_floor().toString() == $datetime.get_floor().toString();
}
}
| op datetime
{$$ = function(k) {
k = safeparse(k);
var result =
$op == '<' ? k.get_floor() < $datetime.get_ceiling()
: $op == '>' ? k.get_ceiling() > $datetime.get_floor()
: $op == '>=' ? k.get_ceiling() >= $datetime.get_floor()
: $op == '<=' ? k.get_floor() <= $datetime.get_ceiling()
: $op == 'to' ? k.get_floor() <= $datetime.get_ceiling()
: $op == 'from' ? k.get_ceiling() >= $datetime.get_floor()
: false;
return result;
}}
| datetime op datetime
{$$ = function(k) {
k = safeparse(k);
var result =
$op == 'to' ? k.get_ceiling() >= $1.get_floor() && k.get_floor() <= $3.get_ceiling()
: false;
return result;
}}
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment