terminals.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { INVALID, Parser, UNRECOGNIZED, VALUE } from '../parser.js';
  2. /**
  3. * Parses a literal value.
  4. * @param value The value to parse
  5. */
  6. export class Literal extends Parser {
  7. _create (value) {
  8. this.value = value;
  9. }
  10. _parse (stream) {
  11. const subStream = stream.fork();
  12. for ( let i=0 ; i < this.value.length ; i++ ) {
  13. let { done, value } = subStream.next();
  14. if ( done ) return UNRECOGNIZED;
  15. if ( this.value[i] !== value ) return UNRECOGNIZED;
  16. }
  17. stream.join(subStream);
  18. return { status: VALUE, $: 'literal', value: this.value };
  19. }
  20. }
  21. /**
  22. * Parses matching characters as a string.
  23. * @param test Function that takes a character, and returns whether to include it.
  24. */
  25. export class StringOf extends Parser {
  26. _create (test) {
  27. this.test = test;
  28. }
  29. _parse (stream) {
  30. const subStream = stream.fork();
  31. let text = '';
  32. while (true) {
  33. let { done, value } = subStream.look();
  34. if ( done ) break;
  35. if ( ! this.test(value) ) break;
  36. subStream.next();
  37. text += value;
  38. }
  39. if (text.length === 0) {
  40. return UNRECOGNIZED;
  41. }
  42. stream.join(subStream);
  43. return { status: VALUE, $: 'stringOf', value: text };
  44. }
  45. }
  46. /**
  47. * Parses an object defined by the symbol registry.
  48. * @param symbolName The name of the symbol to parse.
  49. */
  50. export class Symbol extends Parser {
  51. _create(symbolName) {
  52. this.symbolName = symbolName;
  53. }
  54. _parse (stream) {
  55. const parser = this.symbol_registry[this.symbolName];
  56. if ( ! parser ) {
  57. throw new Error(`No symbol defined named '${this.symbolName}'`);
  58. }
  59. const subStream = stream.fork();
  60. const result = parser.parse(subStream);
  61. if ( result.status === UNRECOGNIZED ) {
  62. return UNRECOGNIZED;
  63. }
  64. if ( result.status === INVALID ) {
  65. return { status: INVALID, value: result };
  66. }
  67. stream.join(subStream);
  68. result.$ = this.symbolName;
  69. return result;
  70. }
  71. }
  72. /**
  73. * Does no parsing and returns a discarded result.
  74. */
  75. export class None extends Parser {
  76. _create () {}
  77. _parse (stream) {
  78. return { status: VALUE, $: 'none', $discard: true };
  79. }
  80. }