Created
December 26, 2018 12:37
-
-
Save francisrstokes/4d5f5b2de9644cf547799e3ac85fc6e2 to your computer and use it in GitHub Desktop.
Arcsecond Article
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { | |
between, | |
many, | |
choice, | |
sequenceOf, | |
char, | |
whitespace, | |
anythingExcept, | |
possibly, | |
regex, | |
digits, | |
anyOfString, | |
str, | |
recursiveParser, | |
sepBy | |
} = require('arcsecond'); | |
/*********************************** | |
Type Containers | |
***********************************/ | |
const makeBasicType = typeName => value => ({ | |
type: typeName, | |
value, | |
toString: () => `${typeName}(${value})` | |
}); | |
const makeMultiType = typeName => values => ({ | |
type: typeName, | |
value: values, | |
toString: () => `${typeName}(${values.map(v => v.toString()).join(', ')})` | |
}); | |
const stringType = makeBasicType('String'); | |
const numberType = makeBasicType('Number'); | |
const booleanType = makeBasicType('Boolean'); | |
const arrayType = makeMultiType('Array'); | |
const objectType = makeMultiType('Object'); | |
const keyValuePair = (key, value) => ({ | |
type: 'KeyValuePair', | |
value: [key, value], | |
toString: () => `KeyValuePair(${key.toString()}, ${value.toString()})` | |
}); | |
const nullType = () => ({ | |
type: 'Null', | |
value: null, | |
toString: () => 'Null' | |
}); | |
/*********************************** | |
Utility Parsers | |
***********************************/ | |
const orEmptyString = parser => possibly (parser) .map(x => (x) ? x : ''); | |
const joinedSequence = parsers => sequenceOf (parsers) .map(x => x.join('')); | |
const joinedMany = parser => many (parser) .map(x => x.join('')); | |
const whitespaceSurrounded = between (whitespace) (whitespace); | |
const betweenQuotes = between (char ('"')) (char ('"')); | |
const betweenSquareBrackets = between (char ('[')) (char (']')); | |
const betweenCurlyBrackets = between (whitespaceSurrounded (char ('{'))) (whitespaceSurrounded(char ('}'))); | |
const commaSeparated = sepBy (whitespaceSurrounded (char (','))); | |
/*********************************** | |
Main Recursive Parser | |
***********************************/ | |
const jsonParser = recursiveParser(() => choice ([ | |
nullParser, | |
trueParser, | |
falseParser, | |
numberParser, | |
stringParser, | |
arrayParser, | |
objectParser | |
])); | |
/*********************************** | |
Strings | |
***********************************/ | |
const stringParser = betweenQuotes (joinedMany (choice ([ | |
joinedSequence ([ | |
char ('\\'), | |
char ('"') | |
]), | |
anythingExcept (char ('"')) | |
]))) .map(stringType); | |
/*********************************** | |
Numbers | |
***********************************/ | |
const numberParser = joinedSequence ([ | |
orEmptyString (char ('-')), | |
choice ([ | |
char ('0'), | |
regex (/^[1-9][0-9]*/) | |
]), | |
orEmptyString (joinedSequence ([ | |
char ('.'), | |
digits | |
])), | |
orEmptyString (joinedSequence([ | |
anyOfString ('eE'), | |
orEmptyString (anyOfString ('-+')), | |
digits | |
])) | |
]) .map (x => numberType(Number(x))); | |
/*********************************** | |
Nulls | |
***********************************/ | |
const nullParser = str ('null') .map(nullType); | |
/*********************************** | |
Booleans | |
***********************************/ | |
const trueParser = str ('true') .map(booleanType); | |
const falseParser = str ('false') .map(booleanType); | |
/*********************************** | |
Arrays | |
***********************************/ | |
const arrayParser = betweenSquareBrackets (commaSeparated (jsonParser)) .map(arrayType); | |
const keyValuePairParser = sequenceOf ([ | |
stringParser, | |
whitespaceSurrounded (char (':')), | |
jsonParser | |
]) .map(([key, _, value]) => keyValuePair(key, value)); | |
/*********************************** | |
Objects | |
***********************************/ | |
const objectParser = betweenCurlyBrackets (commaSeparated (keyValuePairParser)) .map(objectType); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why does
betweenSquareBrackets
not allow whitespace around the square brackets?