// Recursive decent parser for options & arguments // parseOption :: TokenTuple -> List TokenTuple -> List TokenTuple function parseOption(option, rest) { let i=0, cont=true, remaining=rest let optionSet = List.of(option) // Debug check if (R.is(Option)(Tuple.snd(option)) === false) { throw new Error('parseOption has received a token that is not an Option', option) } // _parse :: List TokenTuple -> () const _parse = (tokens) => { // current :: TokenTuple let current = tokens.head() // rest :: List TokenTuple let rest = tokens.tail() // Util function for checking if it's a different token, finishing parsing // notAnotherToken :: Token -> Boolean let notAnotherToken = R.complement( R.anyPass([ R.is(Option), R.is(Command), R.is(Path) ]) ) // isWordAndNotToken :: Token -> Boolean const isWordAndNotToken = R.allPass([ R.is(Word), notAnotherToken, ]) // extractAndTest :: TokenTuple -> Boolean const extractAndTest = R.compose(isWordAndNotToken, Tuple.snd) if (cont === true && extractAndTest(current)) { optionSet = optionSet.concat(List.of(current)) return _parse(rest) } else { cont = false remaining = List.of(current).concat(rest) } } // Start parser if (rest.length() > 0) { _parse(rest) } return Tuple(remaining, optionSet) }
const lexerFn = (char) => { i = i + 1 // Increase our character index // If whitespace, finish building curr and tokenize if (R.test(/[\t\n ]/, char)) { let token = tokenize(curr, i) if (Maybe.isJust(token)) { const charNo = i - curr.length curr = '' // NOTE: This uses unsafe `Maybe.value` property access, as we // have a Maybe.isJust() check above return Just(Tuple(charNo, token.value)) } } // Add our new character to the accumulated to check on next tokenization curr = curr + char return Nothing() }