/*
  Parser
  Parses clean source. Generates clean AST.
*/

// Utility functions

const mayBe = (value, func) => value === null ? null : func(...value)

// Predifined regexes

const idRegex = /^([a-zA-Z]+[a-zA-Z0-9_]*)((.|\n)*)$/
const numRegex = /^([\-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[e][+\-]?\d+)?)((.|\n)*)$/
// const nullRegEx       = /^null\b/i
// const booleanRegEx    = /^(true|false)\b/i
// var stringRegEx     = /^('|').*?[^\\]\1/

/*
  Parser factory. Used to create parsers
  parser.regex - creates parser for given regex
  parser.bind - applies monadic bind on parsers
  parser.all - All parsers supplied MUST match
  parser.any - ANY ONE of the parsers need match
*/

const parser = {}

parser.regex = regex => src => mayBe(
  regex.exec(src),
  (m, val, rest) => [val, rest]
)

parser.bind = (mv, mf) => str => mayBe(
  mv(str),
  (val, rest) => mf(val)(rest)
)

parser.all = (...parsers) => src => {
  var rest = src
  var values = []
  for (let parser of parsers) {
    let result = parser(rest)
    if (result === null) return null
    values.push(result[0])
    rest = result[1]
  }
  return [values, rest]
}

parser.any = (...parsers) => src => {
  for (let parser of parsers) {
    let result = parser(src)
    if (result !== null) return result
  }
  return null
}

/*
  All required parsers are created below
*/

const spaceParser = parser.regex(/^(\s+)((.|\n)*)$/)

const equalSignParser = parser.regex(/^(\s+=\s+)((.|\n)*)$/)

const numberParser = str => mayBe(
  numRegex.exec(str),
  (a, num, rest) => [{type: 'Literal', value: Number(num), raw: num}, rest]
)

const identifierParser = str => mayBe(
  idRegex.exec(str),
  (a, name, rest) => [{type: 'Identifier', name: name}, rest]
)

const expressionParser = parser.any(numberParser)

const declParser = parser.bind(
  parser.bind(
    identifierParser,
    val => str => mayBe(
      equalSignParser(str),
      (v, rest) => [val, rest]
    )
  ),
  val => str => mayBe(
    expressionParser(str),
    (v, rest) => [{type: 'VariableDeclaration',
                   kind: 'const',
                   declarations: [{id: val, init: v}]}, rest]
  )
)

module.exports = function (src) {
  const ast = {type: 'Program', body: []}
  // const [space, rest] = spaceParser(src)
  // console.log(rest)
  const result = declParser(src)
  console.log(result)
  if (result !== null) ast.body.push(result[0])
  return ast
}

@@ -340,19 +340,16 @@
 ull%5Cb/i%0A
-// 
 const bo
@@ -354,20 +354,14 @@
 bool
-ean
 Reg
-E
+e
 x 
-   
 = /%5E
@@ -372,18 +372,24 @@
 e%7Cfalse)
-%5Cb
+(.%7C%5Cn)*$
 /i%0A// va
@@ -1695,24 +1695,146 @@
 %7D, rest%5D%0A)%0A%0A
+const booleanParser = str =%3E mayBe(%0A  boolRegex.exec(str),%0A  (a, bool, rest) =%3E %5B%7Btype: 'Literal', value: bool%7D, rest%5D%0A)%0A%0A
 const expres
@@ -2396,16 +2396,17 @@
 result =
+ 
  declPar

Add boolean Parser