Skip to content

Instantly share code, notes, and snippets.

@francisrstokes
Created December 26, 2018 12:37
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save francisrstokes/4d5f5b2de9644cf547799e3ac85fc6e2 to your computer and use it in GitHub Desktop.
Save francisrstokes/4d5f5b2de9644cf547799e3ac85fc6e2 to your computer and use it in GitHub Desktop.
Arcsecond Article
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);
@craigmc08
Copy link

Why does betweenSquareBrackets not allow whitespace around the square brackets?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment