Select Git revision
helper.ts 14.84 KiB
/**
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Panagiotis Tourlas <panagiot_tourlov@hotmail.com>
* @author Koya Sakuma
*/
// import * as Q from 'parsimmon';
import * as P from '../../mol-util/monadic-parser';
import { MolScriptBuilder } from '../../mol-script/language/builder';
const B = MolScriptBuilder;
import { Expression } from '../language/expression';
import { KeywordDict, PropertyDict, FunctionDict, OperatorList } from './types';
export function escapeRegExp(s: String) {
return String(s).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
}
// Takes a parser for the prefix operator, and a parser for the base thing being
// parsed, and parses as many occurrences as possible of the prefix operator.
// Note that the parser is created using `P.lazy` because it's recursive. It's
// valid for there to be zero occurrences of the prefix operator.
export function prefix(opParser: P.MonadicParser<any>, nextParser: P.MonadicParser<any>, mapFn: any) {
const parser: P.MonadicParser<any> = P.MonadicParser.lazy(() => {
return P.MonadicParser.seq(opParser, parser)
.map(x => mapFn(...x))
.or(nextParser);
});
return parser;
}
// Ideally this function would be just like `PREFIX` but reordered like
// `P.seq(parser, opParser).or(nextParser)`, but that doesn't work. The
// reason for that is that Parsimmon will get stuck in infinite recursion, since
// the very first rule. Inside `parser` is to match parser again. Alternatively,
// you might think to try `nextParser.or(P.seq(parser, opParser))`, but
// that won't work either because in a call to `.or` (aka `P.alt`), Parsimmon
// takes the first possible match, even if subsequent matches are longer, so the
// parser will never actually look far enough ahead to see the postfix
// operators.
export function postfix(opParser: P.MonadicParser<any>, nextParser: P.MonadicParser<any>, mapFn: any) {
// Because we can't use recursion like stated above, we just match a flat list
// of as many occurrences of the postfix operator as possible, then use
// `.reduce` to manually nest the list.
//
// Example:
//
// INPUT :: "4!!!"
// PARSE :: [4, "factorial", "factorial", "factorial"]
// REDUCE :: ["factorial", ["factorial", ["factorial", 4]]]
return P.MonadicParser.seqMap(/* no seqMap() in monadic-parser.ts, any suitable replacement? */
nextParser,
opParser.many(),
(x: any, suffixes: any) =>
suffixes.reduce((acc: any, x: any) => {
return mapFn(x, acc);
}, x)
);
}
// Takes a parser for all the operators at this precedence level, and a parser
// that parsers everything at the next precedence level, and returns a parser
// that parses as many binary operations as possible, associating them to the
// right. (e.g. 1^2^3 is 1^(2^3) not (1^2)^3)
export function binaryRight(opParser: P.MonadicParser<any>, nextParser: P.MonadicParser<any>, mapFn: any) {
const parser: P.MonadicParser<any> = P.MonadicParser.lazy(() =>
nextParser.chain(next =>
P.MonadicParser.seq(
opParser,
P.MonadicParser.of(next),