Browse Source

Variables; Types; Directives;

The parser should now cover everything in the Query Document syntax.
It's kind of ugly though.
bjorn 9 years ago
parent
commit
072164661e
1 changed files with 72 additions and 14 deletions
  1. 72 14
      parse.lua

+ 72 - 14
parse.lua

@@ -95,8 +95,12 @@ local function cField(...)
 
 
   for i = 1, #tokens do
   for i = 1, #tokens do
     local key = tokens[i].kind
     local key = tokens[i].kind
-    if not key and tokens[i][1].kind == 'argument' then
-      key = 'arguments'
+    if not key then
+      if tokens[i][1].kind == 'argument' then
+        key = 'arguments'
+      elseif tokens[i][1].kind == 'directive' then
+        key = 'directives'
+      end
     end
     end
 
 
     field[key] = tokens[i]
     field[key] = tokens[i]
@@ -133,10 +137,17 @@ local function cOperation(...)
       operation = args[1]
       operation = args[1]
     }
     }
 
 
-    if #args >= 3 then
-      result.name, result.selectionSet = unpack(args, 2, 3)
-    else
-      result.selectionSet = args[2]
+    for i = 2, #args do
+      local key = args[i].kind
+      if not key then
+        if args[i][1].kind == 'variableDefinition' then
+          key = 'variableDefinitions'
+        elseif args[i][1].kind == 'directive' then
+          key = 'directives'
+        end
+      end
+
+      result[key] = args[i]
     end
     end
 
 
     return result
     return result
@@ -166,6 +177,20 @@ local function cNamedType(name)
   }
   }
 end
 end
 
 
+local function cListType(type)
+  return {
+    kind = 'listType',
+    type = type
+  }
+end
+
+local function cNonNullType(type)
+  return {
+    kind = 'nonNullType',
+    type = type
+  }
+end
+
 local function cInlineFragment(...)
 local function cInlineFragment(...)
   local args = pack(...)
   local args = pack(...)
   if #args == 2 then
   if #args == 2 then
@@ -182,6 +207,30 @@ local function cInlineFragment(...)
   end
   end
 end
 end
 
 
+local function cVariable(name)
+  return {
+    kind = 'variable',
+    name = name
+  }
+end
+
+local function cVariableDefinition(variable, type, defaultValue)
+  return {
+    kind = 'variableDefinition',
+    variable = variable,
+    type = type,
+    defaultValue = defaultValue
+  }
+end
+
+local function cDirective(name, arguments)
+  return {
+    kind = 'directive',
+    name = name,
+    arguments = arguments
+  }
+end
+
 -- "Terminals"
 -- "Terminals"
 local rawName = R('az', 'AZ') * (P('_') + R('09') + R('az', 'AZ')) ^ 0
 local rawName = R('az', 'AZ') * (P('_') + R('09') + R('az', 'AZ')) ^ 0
 local name = rawName / cName
 local name = rawName / cName
@@ -190,32 +239,41 @@ local integerPart = P('-') ^ -1 * (P('0') + R('19') * R('09') ^ 0)
 local intValue = integerPart / cInt
 local intValue = integerPart / cInt
 local fractionalPart = P('.') * R('09') ^ 1
 local fractionalPart = P('.') * R('09') ^ 1
 local exponentialPart = S('Ee') * S('+-') ^ -1 * R('09') ^ 1
 local exponentialPart = S('Ee') * S('+-') ^ -1 * R('09') ^ 1
-local floatValue = integerPart * (fractionalPart ^ -1 * exponentialPart ^ -1) / cFloat
+local floatValue = integerPart * (fractionalPart + exponentialPart + (fractionalPart * exponentialPart)) / cFloat
 local booleanValue = (P('true') + P('false')) / cBoolean
 local booleanValue = (P('true') + P('false')) / cBoolean
 local stringValue = P('"') * C((P('\\"') + 1 - S('"\n')) ^ 0) * P('"') / cString
 local stringValue = P('"') * C((P('\\"') + 1 - S('"\n')) ^ 0) * P('"') / cString
 local enumValue = (rawName - 'true' - 'false' - 'null') / cEnum
 local enumValue = (rawName - 'true' - 'false' - 'null') / cEnum
-local typeCondition = P('on') * space * name / cNamedType
 local fragmentName = (rawName - 'on') / cName
 local fragmentName = (rawName - 'on') / cName
 local fragmentSpread = space * P('...') * fragmentName / cFragmentSpread
 local fragmentSpread = space * P('...') * fragmentName / cFragmentSpread
 local operationType = C(P('query') + P('mutation'))
 local operationType = C(P('query') + P('mutation'))
+local variable = space * P('$') * name / cVariable
 
 
 -- Nonterminals
 -- Nonterminals
 local graphQL = P {
 local graphQL = P {
   'document',
   'document',
   document = space * Ct((V('definition') * comma * space) ^ 0) / cDocument * -1,
   document = space * Ct((V('definition') * comma * space) ^ 0) / cDocument * -1,
   definition = V('operation') + V('fragmentDefinition'),
   definition = V('operation') + V('fragmentDefinition'),
-  operation = (operationType * space * name ^ -1 * V('selectionSet') + V('selectionSet')) / cOperation,
-  fragmentDefinition = P('fragment') * space * fragmentName * space * typeCondition * space * V('selectionSet') / cFragmentDefinition,
-  inlineFragment = P('...') * space * typeCondition ^ -1 * V('selectionSet') / cInlineFragment,
+  operation = (operationType * space * name ^ -1 * V('variableDefinitions') ^ -1 * V('directives') ^ -1 * V('selectionSet') + V('selectionSet')) / cOperation,
+  fragmentDefinition = P('fragment') * space * fragmentName * space * V('typeCondition') * space * V('selectionSet') / cFragmentDefinition,
+  inlineFragment = P('...') * space * V('typeCondition') ^ -1 * V('selectionSet') / cInlineFragment,
   selectionSet = space * P('{') * space * Ct(V('selection') ^ 0) * space * P('}') / cSelectionSet,
   selectionSet = space * P('{') * space * Ct(V('selection') ^ 0) * space * P('}') / cSelectionSet,
   selection = space * (V('field') + fragmentSpread + V('inlineFragment')),
   selection = space * (V('field') + fragmentSpread + V('inlineFragment')),
-  field = space * alias ^ -1 * name * V('arguments') ^ -1 * V('selectionSet') ^ -1 * comma / cField,
+  field = space * alias ^ -1 * name * V('arguments') ^ -1 * V('directives') ^ -1 * V('selectionSet') ^ -1 * comma / cField,
   argument = space * name * P(':') * V('value') * comma / cArgument,
   argument = space * name * P(':') * V('value') * comma / cArgument,
   arguments = P('(') * Ct(V('argument') ^ 1) * P(')'),
   arguments = P('(') * Ct(V('argument') ^ 1) * P(')'),
-  value = space * (V('objectValue') + V('listValue') + enumValue + stringValue + booleanValue + floatValue + intValue),
+  value = space * (variable + V('objectValue') + V('listValue') + enumValue + stringValue + booleanValue + floatValue + intValue),
   listValue = P('[') * Ct((V('value') * comma) ^ 0) * P(']') / cList,
   listValue = P('[') * Ct((V('value') * comma) ^ 0) * P(']') / cList,
   objectFieldValue = C(rawName) * space * P(':') * space * V('value') * comma / cObjectField,
   objectFieldValue = C(rawName) * space * P(':') * space * V('value') * comma / cObjectField,
-  objectValue = P('{') * space * Ct(V('objectFieldValue') ^ 0) * space * P('}') / cObject
+  objectValue = P('{') * space * Ct(V('objectFieldValue') ^ 0) * space * P('}') / cObject,
+  type = V('nonNullType') + V('listType') + V('namedType'),
+  namedType = name / cNamedType,
+  listType = P('[') * space * V('type') * space * P(']') / cListType,
+  nonNullType = (V('namedType') + V('listType')) * P('!') / cNonNullType,
+  typeCondition = P('on') * space * V('namedType'),
+  variableDefinition = space * variable * space * P(':') * space * V('type') * (space * P('=') * V('value')) ^ -1 * comma * space / cVariableDefinition,
+  variableDefinitions = P('(') * Ct(V('variableDefinition') ^ 1) * P(')'),
+  directive = P('@') * name * V('arguments') ^ -1 / cDirective,
+  directives = space * Ct((V('directive') * comma * space) ^ 1) * space
 }
 }
 
 
 return function(str)
 return function(str)