{"id":17513434,"url":"https://github.com/mepy/nihil","last_synced_at":"2025-04-23T13:17:04.828Z","repository":{"id":143897213,"uuid":"361066545","full_name":"Mepy/nihil","owner":"Mepy","description":"A tiny but elegant parser combinator library written by Mepy","archived":false,"fork":false,"pushed_at":"2022-02-06T16:54:19.000Z","size":34,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-23T13:16:50.726Z","etag":null,"topics":["parser"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mepy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-04-24T04:05:28.000Z","updated_at":"2022-01-22T11:15:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"4c3df4eb-d589-4848-b2b9-f8032281228d","html_url":"https://github.com/Mepy/nihil","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mepy%2Fnihil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mepy%2Fnihil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mepy%2Fnihil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mepy%2Fnihil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mepy","download_url":"https://codeload.github.com/Mepy/nihil/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250439294,"owners_count":21430824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["parser"],"created_at":"2024-10-20T06:26:23.657Z","updated_at":"2025-04-23T13:17:04.809Z","avatar_url":"https://github.com/Mepy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nihil\n## Info\nAuthor = Mepy\n[Github](https://github.com/Mepy) : Language = Engilish, mainly\n[Blog](https://mepy.net/) : Language = Simplified Chinese(简体中文)\n\n## Intro\nWARNING : a TOY project current, do NOT use in production.\n\n```nihil``` is a parser combinator library for Javascript(ES2015+).\n\nnihil is null, nothingness, etc, while ```nihil``` is useful and elegant\n[NPM](https://www.npmjs.com/package/nihil).\n\n```nihil``` is a lot inspired by [bnb](https://github.com/wavebeem/bread-n-butter)\nBut written in the style of FP(Functional Programming), mainly, I thought\ndetails in ## Reference.\n\n\n```nihil``` has zero dependencies and is about 5.2KB(exactly 5291 Bytes) raw Javascript. \nAs for minifying and zipping, I haven't tried it.\n\n```nihil``` source code uses some features of ES2015(or ES6),\nsuch as destructuring assignment, arrow function. \nSo you'd better use modern browser like Chrome, Firefox, etc.\n\n```nihil``` library contains only, maybe you can consider, one object ```nihil```.\nSo it of course supports both Browser and NodeJS.\n\n```nihil``` is elegant and easy to use, try it? -\u003e Read ## Tutorial\n\n## Reference\n```nihil``` is a lot inspired by [bnb](https://github.com/wavebeem/bread-n-butter)\nAt first, I used ```bnb``` for another toy project\nHowever, I met some troubles :\n1. Creating a recursive parser is a little hard\n2. Assign bnb.parser.parse to a variable will throw an error\n   Because ```bnb``` implement parser with class\n   Assign instance.parse to a variable will lose ```this``` pointer\nI decide to implement my own one, and I read the source code of ```bnb```\nBut ```nihil``` is totally new written, I thought it should be NOT a derivative of ```bnb```\nThe similarity between ```nihil``` and ```bnb``` might only be \n```bnb.match(RegExp)``` \u003c=\u003e ```nihil(RegExp)```\nand chain method ```.and```, ```.or```, etc.\n\n## Tutorial\n### ```nihil(RegExp)``` : Regular Expression Parser\nYou can use ```nihil(RegExp)``` to create parsers:\n```js\nnihil(/a+/) // a parser\n```\n\n### ```.try``` \u0026 ```.parse``` : Parsing Raw String\nWith a parser, you can parse raw string with method ```.try``` or ```.parse```: \n```js\nconst a = nihil(/a+/)\na.try(\"aaaa\") // \"aaaa\"\na.try(\"bbbb\") // throw { expected: '/a+/', location: 0 }\na.parse(\"aaaa\") // { right: true, value: 'aaaa' }\na.parse(\"bbbb\") // { right: false, error: { expected: '/a+/', location: 0 } }\n```\nThe difference between them is that ```.try``` would throw error while ```.parse``` would return.\n\nFor convenience, we will use ```.try``` in the following text.\n\n### ```.and``` : Sequential Parser\nYou can use ```nihil.and(RegExp,...)``` to create a sequential parser:\n```js\nnihil.and(/a*/,/b*/,/c*/)\n.try(\"bbbbcccc\") // [ '', 'bbbb', 'cccc' ]\n```\nIf exists a parser ```k```, you can use  ```k.and(parser,...)```:\n```js\nconst k = nihil(/k+/)\nconst g = nihil(/g+/)\nk.and(g,k)\n.try(\"kkkggggkkkk\") // [ 'kkk', 'gggg', 'kkkk' ]\n```\nBut It would trouble you if the second parser is a simple parser generated by ```nihil```\nWell, you can simply enter RegExps in place of simple parsers:\n```js\nk.and(/g+/,k)\n.try(\"kkkggggkkkk\") // [ 'kkk', 'gggg', 'kkkk' ]\n```\n\n### ```.or``` : Choose Parsers\nIf you want to parse \"a\" or \"b\", You can of course use RegExp ```/a|b/```\nBut if you want to parse [one complex language] or [another complex language],\nYou can also do it with a complex RegExp which might bring errors,\nbut using ```nihil.or```, you can implement the same function as ```/a|b/```\nwith well-understanding code style:\n```js\nconst a_b = nihil.or(/a/,/b/)\na_b.try(\"a\") // [ 'a' ] \na_b.try(\"b\") // [ 'b' ] \n```\n\n```.or``` is similar to ```.and```, so you can also do like these:\n```js\nconst a = nihil(/a/)\nconst b = nihil(/b/)\nconst c = nihil(/c/)\na.or(b,c).try(\"c\") // [ 'c' ]\na.or(b,/c/).try(\"c\") // [ 'c' ]\n```\n\nATTENTION : The order of parser makes difference, see ### Larger Precedes.\nThe combined parser will try to parse using from left parser to right parser.\n```js\nnihil.or(/a/,/a+/).parse(\"aaa\") // { right: false, error: { expected: '\u003ceof\u003e', location: 1 } }\nnihil.or(/a+/,/a/).parse(\"aaa\") // { right: true, value: [ 'aaa' ] }\n```\n\nWell, maybe you are considering it is just another style to write RegExp\nand doubting whether it is necessary to learn ```.or``` method.\nWhat if the complex language is not a RE language but a LL(1) language?\nYou can not implement it with RegExp!!!\nRead the following tutorial, you can create a parser of LL(m) .\n(m as big as you want and if your computer can compute it in time.) \n\n### ```.keep``` : Select Parsers\n```.keep``` method is used for selecting parsers according former value.\nWith this, you can implement a LL(m) parser.\nFor example, maybe improper, we implement a LL(1) parser \nwhich accepts a string like 'aA', 'bB', ..., 'zZ'\n```js\nconst lowUp = nihil(/[a-z]/)\n.keep($1=\u003enihil(RegExp($1.toUpperCase())))\n.parse\nlowUp(\"nN\") // { right: true, value: [ 'n', 'N' ] }\nlowUp(\"iJ\") // { right: false, error: { expected: '/I/', location: 1 } }\n```\n\nATTENTION : in ```.keep``` method, you must give a function \nwhich returns a parser but **NOT** a RegExp, \ndifferent from ```.and``` and ```.or```.\n\nAs for LL(m), the format is like this, simply m = 2\n```js\nconst char4 = nihil.and(/./,/./,/./,/./)\n// result of char4 is an array with a length of 4 \u003e m = 2\nconst parser = char4.keep(([$1,$2,$3,$4])=\u003e{\n    if($4=='a'){return nihil(/r/)}\n    else if($3=='b'){return nihil(/s/)}\n    else{return nihil(/t/)}\n}).try\n\n// parser accepts /...ar/, /..b[^a]s/ or /..[^b][^a]t/ \nparser(\"wxyar\"), // [ 'w', 'x', 'y', 'a', 'r' ]\nparser(\"wxbzs\"), // [ 'w', 'x', 'b', 'z', 's' ]\nparser(\"wxyzt\"), // [ 'w', 'x', 'y', 'z', 't' ]\n```\n\nREASON : Why name this method after 'keep'?\nBecause this method **KEEP** the former value (e.g. result of ```char4```)\nCan we choose not to keep it?\nOf course, use ```.drop``` instead of ```.keep```\nBut it is little used in my view.\n\n### ```.map``` : Transform Value\nUntil now, value of result of parsers are all strings.\nSometimes, we need to transform them, e.g. transform ```'3'``` to ```3```\n```js\nnihil(/0|[1-9][0-9]*/) // String of number, decimal\n.map(Number) // from String to Number\n.try(\"3\") // 3\n```\n\n```.map``` could do other things, like verifying the value:\nFor example, we decide to reject 114514\n```js\nconst num = nihil(/0|[1-9][0-9]*/)\n.map(Number)\n.map($1=\u003e{\n        if($1==114514)\n                return undefined\n        else\n                return $1\n})\nnum.and(/\\s+/,num)\n.try(\"114514 3\") // [ undefined, ' ', 3 ]\n```\n\nHowever, you might realize that the parser, \nin fact, replace 114514 with undefined. \nCan we DROP 114514, make the result ```[ ' ', 3 ]```? \nUse ```.drop```.\n\n### ```.drop``` : Intercept Value (Optional)\nExcept that ```.drop``` drops the former parser's result,\nit is nearly the same as ```.keep```\n\nWhat needs to be emphasized is \nthat ```fn``` in ```.drop(fn)``` MUST return a parser\nNEITHER RegExp,  NOR array of values in ```.map```\n\n```nihil.box(value)``` will return a parser \nwhich does nothing but return value,\nso called a box (a parser containing value).\nYou might feels it useful, right?\n\n```js\nconst num = nihil(/0|[1-9][0-9]*/)\n.map(Number)\n.drop($1=\u003e{\n    if($1==114514)\n        return nihil\n    else\n        return nihil.box($1)\n})\n\nconst foo = num.and(/\\s+/,num).try\nfoo(\"114514 3\") // [ ' ', 3]\nfoo(\"10492 3\") // [ 10492, ' ', 3 ]\n```\nBut wait, what is ```nihil``` in ```return nihil```?\n\n### ```nihil``` : NULL Parser\nAs is seen, ```nihil``` acts as a **parser**, doing nothing. \n\nFormly, ```nihil```, as its name, is a nihil (NULL parser, PSEUDO parser).\n\nIt can accept a RegExp and return a parser, which we have been using.\n\n```nihil``` is a parser, so you can use its ```.and```, ```.or```. \nBut ```nihil```'s ```.keep``` , ```.drop``` and ```.map``` must accept a parser first, \nbecause it doesn't return value when parsing. See API.\n\nUntil now, we have nearly been empowered to write LL(∞) parsers. \nBut without knowing the flaw of parser combinator, i.e. the top down parser,\nThe following methods would be hard to make by the above methods.\n\n## Higher Order Tutorial\nFor a quick-look, You can only read built-in method. \nBut reading completely is useful for understanding ```nihil```'s feature.\n\n### ```.sep``` : Seperator Between Parser\nRecall the result of example in ```.drop``` tutorial, ```[ ' ' , 3 ]```\nWe might find that the ' ' is so ugly, we want to drop it! \nOf course, we can use ```.map``` to map the array ```[ ' ' , 3 ]``` to ```[ 3 ]```. \nBut the annoying thing is we need to consider more situations : \n```js\nconst number = nihil(/0|[1-9][0-9]*/).map(Number)\nconst space = nihil(/\\s*/) // accept 0~∞ space(s)\nconst left = \"  3\"\nconst right = \"3 \"\nconst leftright = \" 3  \"\n```\n\n#### using built-in ```.sep```\n```nihil``` implements a built-in method ```.sep``` for parsers: \n```js\nvar parse = number.sep(space).try\nparse(left) // 3\nparse(right) // 3\nparse(leftright) // 3\n```\nBut it hides some interesting features, let's implement our ```.sep```.\n\n#### using simple ```.and```\n```js\n// first method\nvar parse = nihil.and(space, number, space).parse\nparse(left) // { right: false, error: { expected: '/\\\\s*/', location: 3 } }\nparse(right) // { right: true, value: [ 3, ' ' ] }\nparse(leftright) // { right: true, value: [ ' ', 3, '  ' ] } }\n```\nObviously, sometimes it would err.\n\n#### using simple ```.and``` and partial ```.or(nihil)```\n```js\n// first method\nvar parse = nihil.and(space, number, space.or(nihil)).parse\nparse(left) // { right: true, value: [ '  ', 3 ] }\nparse(right) // { right: true, value: [ 3, ' ' ] }\nparse(leftright) // { right: true, value: [ ' ', 3, '  ' ] } }\n```\nWe have solved the problem it errs, but how to map three different cases to the same result ```3```? \nIt is a bit difficult, especially differentiating the first and the second. \n\n#### using ```.drop``` ahead of combining parsers\nWhen meeting \\s*, we drop it.\n```js\nvar space_drop = space.drop(_=\u003enihil);\nvar parse = nihil.and(space_drop, number, space_drop.or(nihil))\n        .map($=\u003e$[0])\n        .parse\nparse(left) // { right: true, value: 3 }\nparse(right) // { right: true, value: 3 }\nparse(leftright) // { right: true, value: 3 }\n```\nFinally, we solve it. \n\n#### feature\n- ```parser.drop(_=\u003enihil)``` can drop the value of the parser\n- ```parser.or(nihil)``` can skip the parser if it couldn't match, similar to the symbol ```?``` in the RegExp.\n\n### ```.loop``` : Recursive Parser\nIf we want to parse ```\" 3 4 5 \"```, \nwe can use ```number.and(number, number)``` with ```.sep```. \nBut if we don't know how many numbers occur? \n```js\nconst array4 = \"3 4   6 4 \"\nconst array2 = \" 5   9\"\n```\n\n#### using built-in ```.loop```\nOf course, there is a built-in ```.loop```: \n```js\nvar array = number.sep(space)\n        .loop()\narray.try(array4) // [ 3, 4, 6, 4 ]\narray.try(array2) // [ 5, 9 ]\n```\nbut it also hides some interesting features, let's implement our ```.loop```.\n\n#### loop = recursion\nAs programmers all know, loop is equal to recusion. \nSo we can implement a recursive parser, the following is a BNF(Backus-Naur Form): \n```BNF\narray ::= number array | nihil\n```\nBut how can ```array``` call itself?\n\n#### straightly calling itself\n```js\nvar array = undefined // ensure array undefined\nvar array = number.sep(space)\n        .and(array)\n        .or(nihil)\n// Thrown:\n// TypeError: Cannot read property 'raw' of undefined\n```\nIt failed, because array is undefined when we define array. \n\n#### using wrapper and closure\nIn Javascript, closure is useful. \nIn this way, an object can be captured by a function. \nWe can use the object in the function when called. \nIn other words, we wrap the object with a function.\n\nWe usually call this trick \"late-bound\" (especially in λ-calculus)\n```js\nvar array = undefined // ensure array undefined\nvar array = number.sep(space)\n        .and(_=\u003earray(_))\n        .or(nihil)\narray.try(array4) // [ 3, [ 4, [ 6, [ 4 ] ] ] ]\narray.try(array2) // [ 5, [ 9 ] ]\n```\nATTENTION : We defer the use time of ```array```! \nIt was called when the arrow function ```_=\u003earray(_)``` called.\n\nWait, is parser a function, now that called with argument ```_```? \nYes, a parser is a function, it accepts ```source``` and return ```value```. \nWe use ```.try``` or ```.parse```, \nbecause ```source``` is a wrapper of ```String```, \nand we also need to wrap ```value```s into results or throw errors.\nSee [nihil.parser](###nihil.parser)\n\n#### unfolding the result\nNoticing that the result is a recursive array, \nwe need to unfold it into a simple array.\n```js\nconst unfold = a=\u003e(a.length == 1)?a:([a[0],...a[1]]) // a means array\nvar array = undefined // ensure array undefined\nvar array = number.sep(space)\n        .and(_=\u003earray(_))\n        .map(unfold)\n        .or(nihil)\narray.try(array4) // [ 3, 4, 6, 4 ]\narray.try(array2) // [ 5, 9 ]\n```\n\n#### feature\n- ```parser``` is indeed a function, we can call it with [source](###nihil.source)\n- ```_=\u003eparser(_)``` can defer the time of using parser.\n- ```unfold``` is needed for maping recursive array to simple array.\n\n### ```.wrap``` : Wrapper Between Parser\nNow, we could parse string such as ```\"3 4   6 4 \"```, ```\" 5   9\"```, etc.\nWe want to add ```\"[\"``` and ```\"]\"``` on the left and right of array.\n\n#### using built-in ```.wrap```\n```js\narray\n        .wrap(/\\[/,/\\]/)\n        .try(\"[3 4   6 4 ]\") // [ 3, 4, 6, 4 ]\n```\n#### using ```.and``` and ```.map```\n```js\nnihil\n        .and(/\\[/,array,/\\]/)\n        .map(([l,v,r])=\u003ev)\n        .try(\"[3 4   6 4 ]\") // [ 3, 4, 6, 4 ]\n```\n```nihil``` indeed uses such a method to offer a handy tool ```.wrap```.\n\n#### feature\n- ```parser.wrap``` is a useful tool.\n\n### Larger Precedes\nLet's run 2 code segments with a slight difference:\n```js\nvar number = nihil(/0|[1-9][0-9]*/).map(Number).sep(/\\s*/)\nnumber.loop().or(number)\n.parse(\"3 4\") // { right: true, value: [ 3, 4 ] }\n```\n```js\nvar number = nihil(/0|[1-9][0-9]*/).map(Number).sep(/\\s*/)\nnumber.or(number.loop())\n.parse(\"3 4\") // { right: false, error: { expected: '\u003ceof\u003e', location: 2 } }\n```\nThe second one is incorrect.\nThe ```number``` parsed the string first and **succueeded**, \nso ```number.loop()``` had no opportunity to parse the raw string. \nHowever, ```number``` could only parse one number, \nso it expected \\\u003ceof\u003e after parsing ```\"3 \"```, but given ```\"4\"```, \nfinally it returned an error.\n\nNotation : \n- P, Q, R, ... are Parsers.\n- P | Q means ```P.or(Q)```\n- L(P) is the language described by P.\n- p ∈ L(P) is a string of the language L(P).\n- p \u003c q means p is a prefix substring of q.\n \nDefinition : P \u003c Q iff L(P) \u003c L(Q) iff ∀q ∈ L(Q), ∃p ∈ L(P), p \u003c q\n\nTheorem : P \u003c Q ⇒ L(P | Q) = L(P)\n\nProof : Omitted.\n\nTherefore, if P \u003c Q, ```P.or(Q)``` acts as ```P```.\n\n#### feature\n- when ```.or``` combining parsers, the larger should precedes. \n\n### Avoid Left Recursion\nRecall the BNF in the loop recursion\n```BNF\narray ::= number array | nihil\n```\nAs a matter of fact, the following BNF is also correct.\n```BNF\narray ::= array number | nihil\n```\nHowever, the corresponding Javascript code is incorrect:\n```js\nvar number = nihil(/0|[1-9][0-9]*/).map(Number).sep(/\\s*/)\nvar array = nihil.and(_=\u003earray(_),number).or(nihil)\narray.try(\"3 4 \")\n// Thrown:\n// RangeError: Maximum call stack size exceeded\n```\nThis is because ```array``` always calling itself, \nmaking the function calling stack overflow.\n\nWe call the first BNF \"right recursion\", the second \"left recursion\". \n\n#### feature\n- when ```.and``` creating recursive parsers, transform left recursion to right recursion.\n\n### Example : Tree Recursion\nThe recursive parser made in the ```.loop``` is linked-list-like. \nNow we implement a tree-like one.\n```js\nvar number = nihil(/0|[1-9][0-9]*/).map(Number)\nvar array = number.or(_=\u003earray(_)).sep(/\\s*/).loop().wrap(/\\[/,/\\]/)\narray.try(\"[ 3 [5[9]] 6 [4 5 ]  ]\") // [ 3, [ 5, [ 9 ] ], 6, [ 4, 5 ] ]\n```\n## Useful Tools\n### ```.lable``` : Label Node\nSometimes we want to add a label to the parser result.\n```js\nvar decimal = nihil(/0|[1-9][0-9]*/).map(Number).label(\"decimal\")\nvar hexadecimal = nihil(/0x(0|[0-9a-fA-F][1-9a-fA-F]*)/).map(Number).label(\"hexadecimal\")\nvar number = decimal.or(hexadecimal)\nnumber.try(\"33\") // { label: 'decimal', value: 33 }\n```\nIn fact, you can use ```.map``` to implement it.\n```js\nparser.label = label=\u003eparser.map(value=\u003e({label,value}))\n```\n### ```.locate``` : Located Parser\nSometimes we want to locate where parser works.\n```js\nvar a = nihil(/a+/)\nvar b = nihil(/b+/).locate()\na.or(b).loop()\n.try(\"aaabbbbaa\") // [ 'aaa', { beg: 3, value: 'bbbb', end: 7 }, 'aa' ]\n```\n\n## Current Bugs\n```js\nvar a = nihil(/a+/).drop(_=\u003enihil)\nvar b = nihil(/b+/)\nb.or(a).sep(/\\s+/).loop().parse(\"aaabbbbaa\") \n// { right: false, error: { expected: '\u003ceof\u003e', location: 3 } }\n```\nThe reason might be that ```.loop``` uses ```nihil.nihil``` to break the looping, while ```.drop``` offers ```nihil``` generating ```nihil.nihil```.\n## API\n\n### ```nihil```\nnihil(parser A)=\u003eparser A\nnihil(source)=\u003enihil.nihil\nnihil(RegExp)=\u003eparser(RE)\n\n### result format\n- ```{right:true, value : ... }``` is the result when parsing succeeded.\n- ```{right:false, error : ... }``` is the result when parsing failed.\n- ```nihil.nihil = { right:true, nihil:true }``` is the result of the **nihil** parser.\n\n### nihil.parser\nIt is the helper function of nihil\nIf you are a new hand of Javascript but familiar with OOP(Object Oriented Programming),\nyou can consider it as ```class parser```\n\nAs a matter of fact, its real member function are ```.try``` and ```parse```\nfor easily parse string and return proper result.\nBecause a parser is a function indeed, you can call it with argument ```source```,\nsee [nihil.source](###nihil.source)\n\nAs for other functions, they are all for convenience of creating parsers\nin the grammar of chain calling. \nYou can intuitively feels it in Tutorial.\nAlso, the source code of ```nihil.parser``` \npromotes your understanding of the whole ```nihil```.\n\n### nihil.source\nLabel the raw string with an ima(a Japanese word, means \"current\") location.\n```js\nconst source = nihil.source(\"abc\") // source =  { raw: \"abc\", ima: 0 }\nconst ab = nihil(/ab/)\nab(source) // { right: true, value: \"ab\" }\n// source =  { raw: \"abc\", ima: 2 }\n```\n\n### nihil.location\nA parser returning the ima location of parsing source as value.\n```js\nconst source = nihil.source(\"abc\") // source =  { raw: \"3\", ima: 0 }\nconst ab = nihil(/ab/)\nab(source)\nnihil.location(source) // {right: true, value: 2}\n// source =  { raw: \"abc\", ima: 2 }\n```\n\n### nihil.and\ninput array of RegExp or parser, return a parser \nwhich parses source sequentially in the order of array\n\n### nihil.or\ninput array of RegExp or parser, return a parser \nwhich tries to parse source from array[0] to array[array.length-1]:=end.\nIf array[k] succeeds, array[k+1],...,end wouldn't be used to parse source.\n\n### nihil.keep\nIt helps implement the parser of LL(∞). \n```nihil.keep``` accepts ```parser``` and \nselecting function ```fn``` \nwith value return by a ```parser``` as argument\nand a parser as return value, and returns a new parser. \n```js\nvar fn = value=\u003eparser\nvar LLm = nihil.keep(parser)(fn)\n```\n\n### nihil.drop\nIt is similar to ```nihil.keep``` with difference \nthat it would DROP the values parsed out by ```parse```\n \n### nihil.map\nUsed to map the value of ```parse``` to the format you like\n```js\nnihil.map(parse)(mapping)\n```\n\n### nihil.sep\nUsed to deal with the ```seperator``` on the left and the right of ```parser```.\n```js\nnihil.sep(parser)(seperator)\n```\n\n### nihil.loop\nUsed to looping parse string with ```parser```.\n```js\nnihil.loop(parser)\n```\n\n### nihil.label\nUsed to label the value of ```parser```.\n```js\nnihil.label(parser)(label)\n```\n\n### nihil.locate\nUsed to locate the value of ```parser```\n```js\nnihil.locate(parser)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmepy%2Fnihil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmepy%2Fnihil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmepy%2Fnihil/lists"}