From 784d48d842734da7b808a28c1675a0c41ca9582f Mon Sep 17 00:00:00 2001 From: Shane Wilson Date: Thu, 5 Feb 2015 11:56:41 -0500 Subject: [PATCH] feat(gql): adds support for top level ops. - Adds support for is, is not, in , not in - Adds support for parens - let AND and OR be used without wrapping in parens. - there is still an issue with lack of operator priority - can still be solved with parens though --- app/scripts/components/gql/gql.directive.ts | 14 +- gql.pegjs | 183 ++++++++++++++------ 2 files changed, 138 insertions(+), 59 deletions(-) diff --git a/app/scripts/components/gql/gql.directive.ts b/app/scripts/components/gql/gql.directive.ts index 52cee7fe7..d9c85112c 100644 --- a/app/scripts/components/gql/gql.directive.ts +++ b/app/scripts/components/gql/gql.directive.ts @@ -10,9 +10,9 @@ module ngApp.components.gql.directives { link: function($scope: ng.IScope) { $scope.query = ""; $scope.onChange = () => { - if ($scope.query[0] !== "(") { - $scope.query = "(" + $scope.query; - } + //if ($scope.query[0] !== "(") { + // $scope.query = "(" + $scope.query; + //} try { $scope.gql = $window.gql.parse($scope.query); console.log($scope.gql); @@ -22,10 +22,10 @@ module ngApp.components.gql.directives { $scope.gql = null; $scope.errorMsg = Error.message; $scope.error = _.pluck(Error.expected, 'value'); - if ($scope.error.length === 1 && $scope.error[0].length === 1) { - $scope.query += $scope.error[0]; - $scope.onChange(); - } + //if ($scope.error.length === 1 && $scope.error[0].length === 1) { + // $scope.query += $scope.error[0]; + // $scope.onChange(); + //} } diff --git a/gql.pegjs b/gql.pegjs index 36263ea67..8f45b698c 100644 --- a/gql.pegjs +++ b/gql.pegjs @@ -1,55 +1,134 @@ -start = sexp - -sexp = "(" ops:ops ")" - { return ops } - -ops = group_op / list_op / value_op - -// Group Operators take >1 sexps -group_op = op:group_op_terms ':' args:group_args - { return {"op": op, "content": args} } - -group_op_terms = "and" / "or" - -group_args = xs:sexps+ x:sexp - { xs.push(x); return xs } - -sexps = xs:(sexp ",") - { return xs[0] } +start + = _* node:node+ _* + { + return node[0]; + } + / _* + { + return {}; + } + / EOF + { + return {}; + } + +node + = group_expr + / exprs + +exprs + = list_expr + / value_expr + / parens + +parens + = "(" node:node ")" + { + return node; + } + +// Group Operators +group_expr + = left:exprs operator:group_operator_expr right:node + { + return { + op: operator, + content: [left, right] + } + } + +group_operator_expr + = _ operator:("or"i / "and"i) _ + { + return operator; + } // List Operators take a field and a list of terms -list_op = op:list_op_terms ":" args:list_args - { return {"op": op, "content": args}} - -list_op_terms = "in" / "out" - -list_args = f:word "," "[" v:terms "]" - { return {"field": f, "value": v }} - +list_expr + = field:unquoted_term operator:list_operator_expr terms:terms + { + return { + op: operator, + content: { + field: field, + terms: terms + } + } + } + +list_operator_expr + = _ operator:list_operators _ + { + return operator; + } + +list_operators + = "not in"i + / "in"i + // Value Operators take a field and a value -value_op = op:value_op_terms ":" args:value_args - { return {"op": op, "content": args}} - -value_op_terms = "is" / "not" / "gt" / "gte" / "lt" / "lte" - -value_args = f:word "," v:term - { return {"field": f, "value": v }} - -arg = xs:(term / sexp) - -terms = xs:_terms+ x:term - { xs.push(x); return xs } - -_terms = xs:(term ',') - {return xs[0] } - -term = word / text - -text = quote .+ quote - -quote = '"' - -word = cs:$char+ - { return cs } - -char = [A-Za-z0-9_-] \ No newline at end of file +value_expr + = field:unquoted_term operator:value_operator_expr term:term + { + return { + op: operator, + content: { + field: field, + term: term + } + } + } + +value_operator_expr + = _ operator:value_operators _ + { + return operator; + } + +value_operators + = "is not"i + / "is"i + / "gte"i + / "gt"i + / "lte"i + / "lt"i + + +terms + = "[" x:term xs:_terms* "]" + { + var ts = [x]; + if (xs.length) { + ts = ts.concat(xs) + } + + return ts; + } + +_terms + = xs:(_ term) + { + return xs[1]; + } + +term + = unquoted_term + / quoted_term + +unquoted_term + = term:$[^: \t\r\n\f\{\}()"+-/^~\[\]]+ + { + return term; + } + +quoted_term + = '"' term:$[^"]+ '"' + { + return term; + } + +_ "whitespace" + = [ \t\r\n\f,]+ + +EOF + = !. \ No newline at end of file