parse.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright (C) 2024 Puter Technologies Inc.
  3. *
  4. * This file is part of Phoenix Shell.
  5. *
  6. * Phoenix Shell is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. export class Parser {
  20. constructor ({
  21. impl,
  22. assign,
  23. }) {
  24. this.impl = impl;
  25. this.assign = assign ?? {};
  26. }
  27. parse (lexer) {
  28. const unadaptedResult = this.impl.parse(lexer);
  29. const pr = unadaptedResult instanceof ParseResult
  30. ? unadaptedResult : new ParseResult(unadaptedResult);
  31. if ( pr.status === ParseResult.VALUE ) {
  32. pr.value = {
  33. ...pr.value,
  34. ...this.assign,
  35. };
  36. }
  37. return pr;
  38. }
  39. }
  40. export class ParseResult {
  41. static UNRECOGNIZED = { name: 'unrecognized' };
  42. static VALUE = { name: 'value' };
  43. static INVALID = { name: 'invalid' };
  44. constructor (value, opt_status) {
  45. if (
  46. value === ParseResult.UNRECOGNIZED ||
  47. value === ParseResult.INVALID
  48. ) {
  49. this.status = value;
  50. return;
  51. }
  52. this.status = opt_status ?? (
  53. value === undefined
  54. ? ParseResult.UNRECOGNIZED
  55. : ParseResult.VALUE
  56. );
  57. this.value = value;
  58. }
  59. }
  60. class ConcreteSyntaxParserDecorator {
  61. constructor (delegate) {
  62. this.delegate = delegate;
  63. }
  64. parse (lexer, ...a) {
  65. const start = lexer.seqNo;
  66. const result = this.delegate.parse(lexer, ...a);
  67. if ( result.status === ParseResult.VALUE ) {
  68. const end = lexer.seqNo;
  69. result.value.$cst = { start, end };
  70. }
  71. return result;
  72. }
  73. }
  74. class RememberSourceParserDecorator {
  75. constructor (delegate) {
  76. this.delegate = delegate;
  77. }
  78. parse (lexer, ...a) {
  79. const start = lexer.seqNo;
  80. const result = this.delegate.parse(lexer, ...a);
  81. if ( result.status === ParseResult.VALUE ) {
  82. const end = lexer.seqNo;
  83. result.value.$source = lexer.reach(start, end);
  84. }
  85. return result;
  86. }
  87. }
  88. export class ParserFactory {
  89. constructor () {
  90. this.concrete = false;
  91. this.rememberSource = false;
  92. }
  93. decorate (obj) {
  94. if ( this.concrete ) {
  95. obj = new ConcreteSyntaxParserDecorator(obj);
  96. }
  97. if ( this.rememberSource ) {
  98. obj = new RememberSourceParserDecorator(obj);
  99. }
  100. return obj;
  101. }
  102. create (cls, parserParams, resultParams) {
  103. parserParams = parserParams ?? {};
  104. resultParams = resultParams ?? {};
  105. resultParams.assign = resultParams.assign ?? {};
  106. const impl = new cls(parserParams);
  107. const parser = new Parser({
  108. impl,
  109. assign: resultParams.assign
  110. });
  111. // return parser;
  112. return this.decorate(parser);
  113. }
  114. }
  115. export class SingleParserFactory {
  116. create () {
  117. throw new Error('abstract create() must be implemented');
  118. }
  119. }
  120. export class AcceptParserUtil {
  121. static adapt (parser) {
  122. if ( parser === undefined ) return undefined;
  123. if ( parser instanceof SingleParserFactory ) {
  124. parser = parser.create();
  125. }
  126. if ( ! (parser instanceof Parser) ) {
  127. parser = new Parser({ impl: parser });
  128. }
  129. return parser;
  130. }
  131. }