123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- /*************************************************************
- *
- * Copyright (c) 2017-2022 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview Symbol map classes.
- *
- * @author v.sorge@mathjax.org (Volker Sorge)
- */
- import {Attributes, Args, ParseMethod, ParseInput, ParseResult} from './Types.js';
- import {Symbol, Macro} from './Symbol.js';
- import {MapHandler} from './MapHandler.js';
- /**
- * SymbolMaps are the base components for the input parsers.
- *
- * They provide a contains method that checks if a map is applicable (contains)
- * a particular string. Implementing classes then perform the actual symbol
- * parsing, from simple regular expression test, straight forward symbol mapping
- * to transformational functionality on the parsed string.
- *
- * @interface
- */
- export interface SymbolMap {
- /**
- * @return {string} The name of the map.
- */
- name: string;
- /**
- * @return {ParseMethod} The default parsing method.
- */
- parser: ParseMethod;
- /**
- * @param {string} symbol A symbol to parse.
- * @return {boolean} True if the symbol map applies to the symbol.
- */
- contains(symbol: string): boolean;
- /**
- * @param {string} symbol A symbol to parse.
- * @return {ParseMethod} A parse method for the symbol.
- */
- parserFor(symbol: string): ParseMethod;
- /**
- * @param {TexParser} env The current parser.
- * @param {string} symbol A symbol to parse.
- * @return {ParseResult} The parsed symbol and the rest of the string.
- */
- parse([env, symbol]: ParseInput): ParseResult;
- }
- /**
- * @param {ParseResult} result The result to check
- * @return {ParseResult} True if result was void, result otherwise
- */
- export function parseResult(result: ParseResult): ParseResult {
- return result === void 0 ? true : result;
- }
- /**
- * Abstract implementation of symbol maps.
- * @template T
- */
- export abstract class AbstractSymbolMap<T> implements SymbolMap {
- /**
- * @constructor
- * @implements {SymbolMap}
- * @param {string} name Name of the mapping.
- * @param {ParseMethod} parser The parser for the mappiong.
- */
- constructor(private _name: string, private _parser: ParseMethod) {
- MapHandler.register(this);
- }
- /**
- * @override
- */
- public get name(): string {
- return this._name;
- }
- /**
- * @override
- */
- public abstract contains(symbol: string): boolean;
- /**
- * @override
- */
- public parserFor(symbol: string) {
- return this.contains(symbol) ? this.parser : null;
- }
- /**
- * @override
- */
- public parse([env, symbol]: ParseInput) {
- let parser = this.parserFor(symbol);
- let mapped = this.lookup(symbol);
- return (parser && mapped) ? parseResult(parser(env, mapped as any)) : null;
- }
- public set parser(parser: ParseMethod) {
- this._parser = parser;
- }
- public get parser(): ParseMethod {
- return this._parser;
- }
- /**
- * @param {string} symbol
- * @return {T}
- */
- public abstract lookup(symbol: string): T;
- }
- /**
- * Regular expressions used for parsing strings.
- */
- export class RegExpMap extends AbstractSymbolMap<string> {
- /**
- * @constructor
- * @extends {AbstractSymbolMap}
- * @param {string} name Name of the mapping.
- * @param {ParseMethod} parser The parser for the mappiong.
- * @param {RegExp} regexp The regular expression.
- */
- constructor(name: string, parser: ParseMethod, private _regExp: RegExp) {
- super(name, parser);
- }
- /**
- * @override
- */
- public contains(symbol: string) {
- return this._regExp.test(symbol);
- }
- /**
- * @override
- */
- public lookup(symbol: string): string {
- return this.contains(symbol) ? symbol : null;
- }
- }
- /**
- * Parse maps associate strings with parsing functionality.
- * @constructor
- * @extends {AbstractSymbolMap}
- * @template K
- */
- export abstract class AbstractParseMap<K> extends AbstractSymbolMap<K> {
- private map: Map<string, K> = new Map<string, K>();
- /**
- * @override
- */
- public lookup(symbol: string): K {
- return this.map.get(symbol);
- }
- /**
- * @override
- */
- public contains(symbol: string) {
- return this.map.has(symbol);
- }
- /**
- * Sets mapping for a symbol.
- * @param {string} symbol The symbol to map.
- * @param {K} object The symbols value in the mapping's codomain.
- */
- public add(symbol: string, object: K) {
- this.map.set(symbol, object);
- }
- /**
- * Removes a symbol from the map
- * @param {string} symbol The symbol to remove
- */
- public remove(symbol: string) {
- this.map.delete(symbol);
- }
- }
- /**
- * Maps symbols that can all be parsed with the same method.
- *
- * @constructor
- * @extends {AbstractParseMap}
- */
- export class CharacterMap extends AbstractParseMap<Symbol> {
- /**
- * @constructor
- * @param {string} name Name of the mapping.
- * @param {ParseMethod} parser The parser for the mapping.
- * @param {JSON} json The JSON representation of the character mapping.
- */
- constructor(name: string, parser: ParseMethod,
- json: {[index: string]: string | [string, Attributes]}) {
- super(name, parser);
- for (const key of Object.keys(json)) {
- let value = json[key];
- let [char, attrs] = (typeof(value) === 'string') ? [value, null] : value;
- let character = new Symbol(key, char, attrs);
- this.add(key, character);
- }
- }
- }
- /**
- * Maps symbols that are delimiters, that are all parsed with the same method.
- *
- * @constructor
- * @extends {CharacterMap}
- */
- export class DelimiterMap extends CharacterMap {
- /**
- * @override
- */
- public parse([env, symbol]: ParseInput) {
- return super.parse([env, '\\' + symbol]);
- }
- }
- /**
- * Maps macros that all bring their own parsing method.
- *
- * @constructor
- * @extends {AbstractParseMap}
- */
- export class MacroMap extends AbstractParseMap<Macro> {
- /**
- * @constructor
- * @param {string} name Name of the mapping.
- * @param {JSON} json The JSON representation of the macro map.
- * @param {Record<string, ParseMethod>} functionMap Collection of parse
- * functions for the single macros.
- */
- constructor(name: string,
- json: {[index: string]: string | Args[]},
- functionMap: Record<string, ParseMethod>) {
- super(name, null);
- for (const key of Object.keys(json)) {
- let value = json[key];
- let [func, ...attrs] = (typeof(value) === 'string') ? [value] : value;
- let character = new Macro(key, functionMap[func as string], attrs);
- this.add(key, character);
- }
- }
- /**
- * @override
- */
- public parserFor(symbol: string) {
- let macro = this.lookup(symbol);
- return macro ? macro.func : null;
- }
- /**
- * @override
- */
- public parse([env, symbol]: ParseInput) {
- let macro = this.lookup(symbol);
- let parser = this.parserFor(symbol);
- if (!macro || !parser) {
- return null;
- }
- return parseResult(parser(env, macro.symbol, ...macro.args));
- }
- }
- /**
- * Maps macros that all bring their own parsing method.
- *
- * @constructor
- * @extends {MacroMap}
- */
- export class CommandMap extends MacroMap {
- /**
- * @override
- */
- public parse([env, symbol]: ParseInput) {
- let macro = this.lookup(symbol);
- let parser = this.parserFor(symbol);
- if (!macro || !parser) {
- return null;
- }
- let saveCommand = env.currentCS;
- env.currentCS = '\\' + symbol;
- let result = parser(env, '\\' + macro.symbol, ...macro.args);
- env.currentCS = saveCommand;
- return parseResult(result);
- }
- }
- /**
- * Maps macros for environments. It has a general parsing method for
- * environments, i.e., one that deals with begin/end, and each environment has
- * its own parsing method returning the content.
- *
- * @constructor
- * @extends {MacroMap}
- */
- export class EnvironmentMap extends MacroMap {
- /**
- * @constructor
- * @param {string} name Name of the mapping.
- * @param {ParseMethod} parser The parser for the environments.
- * @param {JSON} json The JSON representation of the macro map.
- * @param {Record<string, ParseMethod>} functionMap Collection of parse
- * functions for the single macros.
- */
- constructor(name: string,
- parser: ParseMethod,
- json: {[index: string]: string | Args[]},
- functionMap: Record<string, ParseMethod>) {
- super(name, json, functionMap);
- this.parser = parser;
- }
- /**
- * @override
- */
- public parse([env, symbol]: ParseInput) {
- let macro = this.lookup(symbol);
- let envParser = this.parserFor(symbol);
- if (!macro || !envParser) {
- return null;
- }
- return parseResult(this.parser(env, macro.symbol, envParser, macro.args));
- }
- }
|