parse.js 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.createParse = void 0;
  7. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  8. var _factory = require("../utils/factory.js");
  9. var _is = require("../utils/is.js");
  10. var _collection = require("../utils/collection.js");
  11. var _object = require("../utils/object.js");
  12. var name = 'parse';
  13. var dependencies = ['typed', 'numeric', 'config', 'AccessorNode', 'ArrayNode', 'AssignmentNode', 'BlockNode', 'ConditionalNode', 'ConstantNode', 'FunctionAssignmentNode', 'FunctionNode', 'IndexNode', 'ObjectNode', 'OperatorNode', 'ParenthesisNode', 'RangeNode', 'RelationalNode', 'SymbolNode'];
  14. var createParse = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
  15. var typed = _ref.typed,
  16. numeric = _ref.numeric,
  17. config = _ref.config,
  18. AccessorNode = _ref.AccessorNode,
  19. ArrayNode = _ref.ArrayNode,
  20. AssignmentNode = _ref.AssignmentNode,
  21. BlockNode = _ref.BlockNode,
  22. ConditionalNode = _ref.ConditionalNode,
  23. ConstantNode = _ref.ConstantNode,
  24. FunctionAssignmentNode = _ref.FunctionAssignmentNode,
  25. FunctionNode = _ref.FunctionNode,
  26. IndexNode = _ref.IndexNode,
  27. ObjectNode = _ref.ObjectNode,
  28. OperatorNode = _ref.OperatorNode,
  29. ParenthesisNode = _ref.ParenthesisNode,
  30. RangeNode = _ref.RangeNode,
  31. RelationalNode = _ref.RelationalNode,
  32. SymbolNode = _ref.SymbolNode;
  33. /**
  34. * Parse an expression. Returns a node tree, which can be evaluated by
  35. * invoking node.evaluate().
  36. *
  37. * Note the evaluating arbitrary expressions may involve security risks,
  38. * see [https://mathjs.org/docs/expressions/security.html](https://mathjs.org/docs/expressions/security.html) for more information.
  39. *
  40. * Syntax:
  41. *
  42. * math.parse(expr)
  43. * math.parse(expr, options)
  44. * math.parse([expr1, expr2, expr3, ...])
  45. * math.parse([expr1, expr2, expr3, ...], options)
  46. *
  47. * Example:
  48. *
  49. * const node1 = math.parse('sqrt(3^2 + 4^2)')
  50. * node1.compile().evaluate() // 5
  51. *
  52. * let scope = {a:3, b:4}
  53. * const node2 = math.parse('a * b') // 12
  54. * const code2 = node2.compile()
  55. * code2.evaluate(scope) // 12
  56. * scope.a = 5
  57. * code2.evaluate(scope) // 20
  58. *
  59. * const nodes = math.parse(['a = 3', 'b = 4', 'a * b'])
  60. * nodes[2].compile().evaluate() // 12
  61. *
  62. * See also:
  63. *
  64. * evaluate, compile
  65. *
  66. * @param {string | string[] | Matrix} expr Expression to be parsed
  67. * @param {{nodes: Object<string, Node>}} [options] Available options:
  68. * - `nodes` a set of custom nodes
  69. * @return {Node | Node[]} node
  70. * @throws {Error}
  71. */
  72. var parse = typed(name, {
  73. string: function string(expression) {
  74. return parseStart(expression, {});
  75. },
  76. 'Array | Matrix': function ArrayMatrix(expressions) {
  77. return parseMultiple(expressions, {});
  78. },
  79. 'string, Object': function stringObject(expression, options) {
  80. var extraNodes = options.nodes !== undefined ? options.nodes : {};
  81. return parseStart(expression, extraNodes);
  82. },
  83. 'Array | Matrix, Object': parseMultiple
  84. });
  85. function parseMultiple(expressions) {
  86. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  87. var extraNodes = options.nodes !== undefined ? options.nodes : {};
  88. // parse an array or matrix with expressions
  89. return (0, _collection.deepMap)(expressions, function (elem) {
  90. if (typeof elem !== 'string') throw new TypeError('String expected');
  91. return parseStart(elem, extraNodes);
  92. });
  93. }
  94. // token types enumeration
  95. var TOKENTYPE = {
  96. NULL: 0,
  97. DELIMITER: 1,
  98. NUMBER: 2,
  99. SYMBOL: 3,
  100. UNKNOWN: 4
  101. };
  102. // map with all delimiters
  103. var DELIMITERS = {
  104. ',': true,
  105. '(': true,
  106. ')': true,
  107. '[': true,
  108. ']': true,
  109. '{': true,
  110. '}': true,
  111. '"': true,
  112. '\'': true,
  113. ';': true,
  114. '+': true,
  115. '-': true,
  116. '*': true,
  117. '.*': true,
  118. '/': true,
  119. './': true,
  120. '%': true,
  121. '^': true,
  122. '.^': true,
  123. '~': true,
  124. '!': true,
  125. '&': true,
  126. '|': true,
  127. '^|': true,
  128. '=': true,
  129. ':': true,
  130. '?': true,
  131. '==': true,
  132. '!=': true,
  133. '<': true,
  134. '>': true,
  135. '<=': true,
  136. '>=': true,
  137. '<<': true,
  138. '>>': true,
  139. '>>>': true
  140. };
  141. // map with all named delimiters
  142. var NAMED_DELIMITERS = {
  143. mod: true,
  144. to: true,
  145. "in": true,
  146. and: true,
  147. xor: true,
  148. or: true,
  149. not: true
  150. };
  151. var CONSTANTS = {
  152. "true": true,
  153. "false": false,
  154. "null": null,
  155. undefined: undefined
  156. };
  157. var NUMERIC_CONSTANTS = ['NaN', 'Infinity'];
  158. function initialState() {
  159. return {
  160. extraNodes: {},
  161. // current extra nodes, must be careful not to mutate
  162. expression: '',
  163. // current expression
  164. comment: '',
  165. // last parsed comment
  166. index: 0,
  167. // current index in expr
  168. token: '',
  169. // current token
  170. tokenType: TOKENTYPE.NULL,
  171. // type of the token
  172. nestingLevel: 0,
  173. // level of nesting inside parameters, used to ignore newline characters
  174. conditionalLevel: null // when a conditional is being parsed, the level of the conditional is stored here
  175. };
  176. }
  177. /**
  178. * View upto `length` characters of the expression starting at the current character.
  179. *
  180. * @param {Object} state
  181. * @param {number} [length=1] Number of characters to view
  182. * @returns {string}
  183. * @private
  184. */
  185. function currentString(state, length) {
  186. return state.expression.substr(state.index, length);
  187. }
  188. /**
  189. * View the current character. Returns '' if end of expression is reached.
  190. *
  191. * @param {Object} state
  192. * @returns {string}
  193. * @private
  194. */
  195. function currentCharacter(state) {
  196. return currentString(state, 1);
  197. }
  198. /**
  199. * Get the next character from the expression.
  200. * The character is stored into the char c. If the end of the expression is
  201. * reached, the function puts an empty string in c.
  202. * @private
  203. */
  204. function next(state) {
  205. state.index++;
  206. }
  207. /**
  208. * Preview the previous character from the expression.
  209. * @return {string} cNext
  210. * @private
  211. */
  212. function prevCharacter(state) {
  213. return state.expression.charAt(state.index - 1);
  214. }
  215. /**
  216. * Preview the next character from the expression.
  217. * @return {string} cNext
  218. * @private
  219. */
  220. function nextCharacter(state) {
  221. return state.expression.charAt(state.index + 1);
  222. }
  223. /**
  224. * Get next token in the current string expr.
  225. * The token and token type are available as token and tokenType
  226. * @private
  227. */
  228. function getToken(state) {
  229. state.tokenType = TOKENTYPE.NULL;
  230. state.token = '';
  231. state.comment = '';
  232. // skip over ignored characters:
  233. while (true) {
  234. // comments:
  235. if (currentCharacter(state) === '#') {
  236. while (currentCharacter(state) !== '\n' && currentCharacter(state) !== '') {
  237. state.comment += currentCharacter(state);
  238. next(state);
  239. }
  240. }
  241. // whitespace: space, tab, and newline when inside parameters
  242. if (parse.isWhitespace(currentCharacter(state), state.nestingLevel)) {
  243. next(state);
  244. } else {
  245. break;
  246. }
  247. }
  248. // check for end of expression
  249. if (currentCharacter(state) === '') {
  250. // token is still empty
  251. state.tokenType = TOKENTYPE.DELIMITER;
  252. return;
  253. }
  254. // check for new line character
  255. if (currentCharacter(state) === '\n' && !state.nestingLevel) {
  256. state.tokenType = TOKENTYPE.DELIMITER;
  257. state.token = currentCharacter(state);
  258. next(state);
  259. return;
  260. }
  261. var c1 = currentCharacter(state);
  262. var c2 = currentString(state, 2);
  263. var c3 = currentString(state, 3);
  264. if (c3.length === 3 && DELIMITERS[c3]) {
  265. state.tokenType = TOKENTYPE.DELIMITER;
  266. state.token = c3;
  267. next(state);
  268. next(state);
  269. next(state);
  270. return;
  271. }
  272. // check for delimiters consisting of 2 characters
  273. if (c2.length === 2 && DELIMITERS[c2]) {
  274. state.tokenType = TOKENTYPE.DELIMITER;
  275. state.token = c2;
  276. next(state);
  277. next(state);
  278. return;
  279. }
  280. // check for delimiters consisting of 1 character
  281. if (DELIMITERS[c1]) {
  282. state.tokenType = TOKENTYPE.DELIMITER;
  283. state.token = c1;
  284. next(state);
  285. return;
  286. }
  287. // check for a number
  288. if (parse.isDigitDot(c1)) {
  289. state.tokenType = TOKENTYPE.NUMBER;
  290. // check for binary, octal, or hex
  291. var _c = currentString(state, 2);
  292. if (_c === '0b' || _c === '0o' || _c === '0x') {
  293. state.token += currentCharacter(state);
  294. next(state);
  295. state.token += currentCharacter(state);
  296. next(state);
  297. while (parse.isHexDigit(currentCharacter(state))) {
  298. state.token += currentCharacter(state);
  299. next(state);
  300. }
  301. if (currentCharacter(state) === '.') {
  302. // this number has a radix point
  303. state.token += '.';
  304. next(state);
  305. // get the digits after the radix
  306. while (parse.isHexDigit(currentCharacter(state))) {
  307. state.token += currentCharacter(state);
  308. next(state);
  309. }
  310. } else if (currentCharacter(state) === 'i') {
  311. // this number has a word size suffix
  312. state.token += 'i';
  313. next(state);
  314. // get the word size
  315. while (parse.isDigit(currentCharacter(state))) {
  316. state.token += currentCharacter(state);
  317. next(state);
  318. }
  319. }
  320. return;
  321. }
  322. // get number, can have a single dot
  323. if (currentCharacter(state) === '.') {
  324. state.token += currentCharacter(state);
  325. next(state);
  326. if (!parse.isDigit(currentCharacter(state))) {
  327. // this is no number, it is just a dot (can be dot notation)
  328. state.tokenType = TOKENTYPE.DELIMITER;
  329. return;
  330. }
  331. } else {
  332. while (parse.isDigit(currentCharacter(state))) {
  333. state.token += currentCharacter(state);
  334. next(state);
  335. }
  336. if (parse.isDecimalMark(currentCharacter(state), nextCharacter(state))) {
  337. state.token += currentCharacter(state);
  338. next(state);
  339. }
  340. }
  341. while (parse.isDigit(currentCharacter(state))) {
  342. state.token += currentCharacter(state);
  343. next(state);
  344. }
  345. // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4"
  346. if (currentCharacter(state) === 'E' || currentCharacter(state) === 'e') {
  347. if (parse.isDigit(nextCharacter(state)) || nextCharacter(state) === '-' || nextCharacter(state) === '+') {
  348. state.token += currentCharacter(state);
  349. next(state);
  350. if (currentCharacter(state) === '+' || currentCharacter(state) === '-') {
  351. state.token += currentCharacter(state);
  352. next(state);
  353. }
  354. // Scientific notation MUST be followed by an exponent
  355. if (!parse.isDigit(currentCharacter(state))) {
  356. throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"');
  357. }
  358. while (parse.isDigit(currentCharacter(state))) {
  359. state.token += currentCharacter(state);
  360. next(state);
  361. }
  362. if (parse.isDecimalMark(currentCharacter(state), nextCharacter(state))) {
  363. throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"');
  364. }
  365. } else if (nextCharacter(state) === '.') {
  366. next(state);
  367. throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"');
  368. }
  369. }
  370. return;
  371. }
  372. // check for variables, functions, named operators
  373. if (parse.isAlpha(currentCharacter(state), prevCharacter(state), nextCharacter(state))) {
  374. while (parse.isAlpha(currentCharacter(state), prevCharacter(state), nextCharacter(state)) || parse.isDigit(currentCharacter(state))) {
  375. state.token += currentCharacter(state);
  376. next(state);
  377. }
  378. if ((0, _object.hasOwnProperty)(NAMED_DELIMITERS, state.token)) {
  379. state.tokenType = TOKENTYPE.DELIMITER;
  380. } else {
  381. state.tokenType = TOKENTYPE.SYMBOL;
  382. }
  383. return;
  384. }
  385. // something unknown is found, wrong characters -> a syntax error
  386. state.tokenType = TOKENTYPE.UNKNOWN;
  387. while (currentCharacter(state) !== '') {
  388. state.token += currentCharacter(state);
  389. next(state);
  390. }
  391. throw createSyntaxError(state, 'Syntax error in part "' + state.token + '"');
  392. }
  393. /**
  394. * Get next token and skip newline tokens
  395. */
  396. function getTokenSkipNewline(state) {
  397. do {
  398. getToken(state);
  399. } while (state.token === '\n'); // eslint-disable-line no-unmodified-loop-condition
  400. }
  401. /**
  402. * Open parameters.
  403. * New line characters will be ignored until closeParams(state) is called
  404. */
  405. function openParams(state) {
  406. state.nestingLevel++;
  407. }
  408. /**
  409. * Close parameters.
  410. * New line characters will no longer be ignored
  411. */
  412. function closeParams(state) {
  413. state.nestingLevel--;
  414. }
  415. /**
  416. * Checks whether the current character `c` is a valid alpha character:
  417. *
  418. * - A latin letter (upper or lower case) Ascii: a-z, A-Z
  419. * - An underscore Ascii: _
  420. * - A dollar sign Ascii: $
  421. * - A latin letter with accents Unicode: \u00C0 - \u02AF
  422. * - A greek letter Unicode: \u0370 - \u03FF
  423. * - A mathematical alphanumeric symbol Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points
  424. *
  425. * The previous and next characters are needed to determine whether
  426. * this character is part of a unicode surrogate pair.
  427. *
  428. * @param {string} c Current character in the expression
  429. * @param {string} cPrev Previous character
  430. * @param {string} cNext Next character
  431. * @return {boolean}
  432. */
  433. parse.isAlpha = function isAlpha(c, cPrev, cNext) {
  434. return parse.isValidLatinOrGreek(c) || parse.isValidMathSymbol(c, cNext) || parse.isValidMathSymbol(cPrev, c);
  435. };
  436. /**
  437. * Test whether a character is a valid latin, greek, or letter-like character
  438. * @param {string} c
  439. * @return {boolean}
  440. */
  441. parse.isValidLatinOrGreek = function isValidLatinOrGreek(c) {
  442. return /^[a-zA-Z_$\u00C0-\u02AF\u0370-\u03FF\u2100-\u214F]$/.test(c);
  443. };
  444. /**
  445. * Test whether two given 16 bit characters form a surrogate pair of a
  446. * unicode math symbol.
  447. *
  448. * https://unicode-table.com/en/
  449. * https://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode
  450. *
  451. * Note: In ES6 will be unicode aware:
  452. * https://stackoverflow.com/questions/280712/javascript-unicode-regexes
  453. * https://mathiasbynens.be/notes/es6-unicode-regex
  454. *
  455. * @param {string} high
  456. * @param {string} low
  457. * @return {boolean}
  458. */
  459. parse.isValidMathSymbol = function isValidMathSymbol(high, low) {
  460. return /^[\uD835]$/.test(high) && /^[\uDC00-\uDFFF]$/.test(low) && /^[^\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]$/.test(low);
  461. };
  462. /**
  463. * Check whether given character c is a white space character: space, tab, or enter
  464. * @param {string} c
  465. * @param {number} nestingLevel
  466. * @return {boolean}
  467. */
  468. parse.isWhitespace = function isWhitespace(c, nestingLevel) {
  469. // TODO: also take '\r' carriage return as newline? Or does that give problems on mac?
  470. return c === ' ' || c === '\t' || c === '\n' && nestingLevel > 0;
  471. };
  472. /**
  473. * Test whether the character c is a decimal mark (dot).
  474. * This is the case when it's not the start of a delimiter '.*', './', or '.^'
  475. * @param {string} c
  476. * @param {string} cNext
  477. * @return {boolean}
  478. */
  479. parse.isDecimalMark = function isDecimalMark(c, cNext) {
  480. return c === '.' && cNext !== '/' && cNext !== '*' && cNext !== '^';
  481. };
  482. /**
  483. * checks if the given char c is a digit or dot
  484. * @param {string} c a string with one character
  485. * @return {boolean}
  486. */
  487. parse.isDigitDot = function isDigitDot(c) {
  488. return c >= '0' && c <= '9' || c === '.';
  489. };
  490. /**
  491. * checks if the given char c is a digit
  492. * @param {string} c a string with one character
  493. * @return {boolean}
  494. */
  495. parse.isDigit = function isDigit(c) {
  496. return c >= '0' && c <= '9';
  497. };
  498. /**
  499. * checks if the given char c is a hex digit
  500. * @param {string} c a string with one character
  501. * @return {boolean}
  502. */
  503. parse.isHexDigit = function isHexDigit(c) {
  504. return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
  505. };
  506. /**
  507. * Start of the parse levels below, in order of precedence
  508. * @return {Node} node
  509. * @private
  510. */
  511. function parseStart(expression, extraNodes) {
  512. var state = initialState();
  513. (0, _extends2["default"])(state, {
  514. expression: expression,
  515. extraNodes: extraNodes
  516. });
  517. getToken(state);
  518. var node = parseBlock(state);
  519. // check for garbage at the end of the expression
  520. // an expression ends with a empty character '' and tokenType DELIMITER
  521. if (state.token !== '') {
  522. if (state.tokenType === TOKENTYPE.DELIMITER) {
  523. // user entered a not existing operator like "//"
  524. // TODO: give hints for aliases, for example with "<>" give as hint " did you mean !== ?"
  525. throw createError(state, 'Unexpected operator ' + state.token);
  526. } else {
  527. throw createSyntaxError(state, 'Unexpected part "' + state.token + '"');
  528. }
  529. }
  530. return node;
  531. }
  532. /**
  533. * Parse a block with expressions. Expressions can be separated by a newline
  534. * character '\n', or by a semicolon ';'. In case of a semicolon, no output
  535. * of the preceding line is returned.
  536. * @return {Node} node
  537. * @private
  538. */
  539. function parseBlock(state) {
  540. var node;
  541. var blocks = [];
  542. var visible;
  543. if (state.token !== '' && state.token !== '\n' && state.token !== ';') {
  544. node = parseAssignment(state);
  545. if (state.comment) {
  546. node.comment = state.comment;
  547. }
  548. }
  549. // TODO: simplify this loop
  550. while (state.token === '\n' || state.token === ';') {
  551. // eslint-disable-line no-unmodified-loop-condition
  552. if (blocks.length === 0 && node) {
  553. visible = state.token !== ';';
  554. blocks.push({
  555. node: node,
  556. visible: visible
  557. });
  558. }
  559. getToken(state);
  560. if (state.token !== '\n' && state.token !== ';' && state.token !== '') {
  561. node = parseAssignment(state);
  562. if (state.comment) {
  563. node.comment = state.comment;
  564. }
  565. visible = state.token !== ';';
  566. blocks.push({
  567. node: node,
  568. visible: visible
  569. });
  570. }
  571. }
  572. if (blocks.length > 0) {
  573. return new BlockNode(blocks);
  574. } else {
  575. if (!node) {
  576. node = new ConstantNode(undefined);
  577. if (state.comment) {
  578. node.comment = state.comment;
  579. }
  580. }
  581. return node;
  582. }
  583. }
  584. /**
  585. * Assignment of a function or variable,
  586. * - can be a variable like 'a=2.3'
  587. * - or a updating an existing variable like 'matrix(2,3:5)=[6,7,8]'
  588. * - defining a function like 'f(x) = x^2'
  589. * @return {Node} node
  590. * @private
  591. */
  592. function parseAssignment(state) {
  593. var name, args, value, valid;
  594. var node = parseConditional(state);
  595. if (state.token === '=') {
  596. if ((0, _is.isSymbolNode)(node)) {
  597. // parse a variable assignment like 'a = 2/3'
  598. name = node.name;
  599. getTokenSkipNewline(state);
  600. value = parseAssignment(state);
  601. return new AssignmentNode(new SymbolNode(name), value);
  602. } else if ((0, _is.isAccessorNode)(node)) {
  603. // parse a matrix subset assignment like 'A[1,2] = 4'
  604. getTokenSkipNewline(state);
  605. value = parseAssignment(state);
  606. return new AssignmentNode(node.object, node.index, value);
  607. } else if ((0, _is.isFunctionNode)(node) && (0, _is.isSymbolNode)(node.fn)) {
  608. // parse function assignment like 'f(x) = x^2'
  609. valid = true;
  610. args = [];
  611. name = node.name;
  612. node.args.forEach(function (arg, index) {
  613. if ((0, _is.isSymbolNode)(arg)) {
  614. args[index] = arg.name;
  615. } else {
  616. valid = false;
  617. }
  618. });
  619. if (valid) {
  620. getTokenSkipNewline(state);
  621. value = parseAssignment(state);
  622. return new FunctionAssignmentNode(name, args, value);
  623. }
  624. }
  625. throw createSyntaxError(state, 'Invalid left hand side of assignment operator =');
  626. }
  627. return node;
  628. }
  629. /**
  630. * conditional operation
  631. *
  632. * condition ? truePart : falsePart
  633. *
  634. * Note: conditional operator is right-associative
  635. *
  636. * @return {Node} node
  637. * @private
  638. */
  639. function parseConditional(state) {
  640. var node = parseLogicalOr(state);
  641. while (state.token === '?') {
  642. // eslint-disable-line no-unmodified-loop-condition
  643. // set a conditional level, the range operator will be ignored as long
  644. // as conditionalLevel === state.nestingLevel.
  645. var prev = state.conditionalLevel;
  646. state.conditionalLevel = state.nestingLevel;
  647. getTokenSkipNewline(state);
  648. var condition = node;
  649. var trueExpr = parseAssignment(state);
  650. if (state.token !== ':') throw createSyntaxError(state, 'False part of conditional expression expected');
  651. state.conditionalLevel = null;
  652. getTokenSkipNewline(state);
  653. var falseExpr = parseAssignment(state); // Note: check for conditional operator again, right associativity
  654. node = new ConditionalNode(condition, trueExpr, falseExpr);
  655. // restore the previous conditional level
  656. state.conditionalLevel = prev;
  657. }
  658. return node;
  659. }
  660. /**
  661. * logical or, 'x or y'
  662. * @return {Node} node
  663. * @private
  664. */
  665. function parseLogicalOr(state) {
  666. var node = parseLogicalXor(state);
  667. while (state.token === 'or') {
  668. // eslint-disable-line no-unmodified-loop-condition
  669. getTokenSkipNewline(state);
  670. node = new OperatorNode('or', 'or', [node, parseLogicalXor(state)]);
  671. }
  672. return node;
  673. }
  674. /**
  675. * logical exclusive or, 'x xor y'
  676. * @return {Node} node
  677. * @private
  678. */
  679. function parseLogicalXor(state) {
  680. var node = parseLogicalAnd(state);
  681. while (state.token === 'xor') {
  682. // eslint-disable-line no-unmodified-loop-condition
  683. getTokenSkipNewline(state);
  684. node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd(state)]);
  685. }
  686. return node;
  687. }
  688. /**
  689. * logical and, 'x and y'
  690. * @return {Node} node
  691. * @private
  692. */
  693. function parseLogicalAnd(state) {
  694. var node = parseBitwiseOr(state);
  695. while (state.token === 'and') {
  696. // eslint-disable-line no-unmodified-loop-condition
  697. getTokenSkipNewline(state);
  698. node = new OperatorNode('and', 'and', [node, parseBitwiseOr(state)]);
  699. }
  700. return node;
  701. }
  702. /**
  703. * bitwise or, 'x | y'
  704. * @return {Node} node
  705. * @private
  706. */
  707. function parseBitwiseOr(state) {
  708. var node = parseBitwiseXor(state);
  709. while (state.token === '|') {
  710. // eslint-disable-line no-unmodified-loop-condition
  711. getTokenSkipNewline(state);
  712. node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor(state)]);
  713. }
  714. return node;
  715. }
  716. /**
  717. * bitwise exclusive or (xor), 'x ^| y'
  718. * @return {Node} node
  719. * @private
  720. */
  721. function parseBitwiseXor(state) {
  722. var node = parseBitwiseAnd(state);
  723. while (state.token === '^|') {
  724. // eslint-disable-line no-unmodified-loop-condition
  725. getTokenSkipNewline(state);
  726. node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd(state)]);
  727. }
  728. return node;
  729. }
  730. /**
  731. * bitwise and, 'x & y'
  732. * @return {Node} node
  733. * @private
  734. */
  735. function parseBitwiseAnd(state) {
  736. var node = parseRelational(state);
  737. while (state.token === '&') {
  738. // eslint-disable-line no-unmodified-loop-condition
  739. getTokenSkipNewline(state);
  740. node = new OperatorNode('&', 'bitAnd', [node, parseRelational(state)]);
  741. }
  742. return node;
  743. }
  744. /**
  745. * Parse a chained conditional, like 'a > b >= c'
  746. * @return {Node} node
  747. */
  748. function parseRelational(state) {
  749. var params = [parseShift(state)];
  750. var conditionals = [];
  751. var operators = {
  752. '==': 'equal',
  753. '!=': 'unequal',
  754. '<': 'smaller',
  755. '>': 'larger',
  756. '<=': 'smallerEq',
  757. '>=': 'largerEq'
  758. };
  759. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  760. // eslint-disable-line no-unmodified-loop-condition
  761. var cond = {
  762. name: state.token,
  763. fn: operators[state.token]
  764. };
  765. conditionals.push(cond);
  766. getTokenSkipNewline(state);
  767. params.push(parseShift(state));
  768. }
  769. if (params.length === 1) {
  770. return params[0];
  771. } else if (params.length === 2) {
  772. return new OperatorNode(conditionals[0].name, conditionals[0].fn, params);
  773. } else {
  774. return new RelationalNode(conditionals.map(function (c) {
  775. return c.fn;
  776. }), params);
  777. }
  778. }
  779. /**
  780. * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift
  781. * @return {Node} node
  782. * @private
  783. */
  784. function parseShift(state) {
  785. var node, name, fn, params;
  786. node = parseConversion(state);
  787. var operators = {
  788. '<<': 'leftShift',
  789. '>>': 'rightArithShift',
  790. '>>>': 'rightLogShift'
  791. };
  792. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  793. name = state.token;
  794. fn = operators[name];
  795. getTokenSkipNewline(state);
  796. params = [node, parseConversion(state)];
  797. node = new OperatorNode(name, fn, params);
  798. }
  799. return node;
  800. }
  801. /**
  802. * conversion operators 'to' and 'in'
  803. * @return {Node} node
  804. * @private
  805. */
  806. function parseConversion(state) {
  807. var node, name, fn, params;
  808. node = parseRange(state);
  809. var operators = {
  810. to: 'to',
  811. "in": 'to' // alias of 'to'
  812. };
  813. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  814. name = state.token;
  815. fn = operators[name];
  816. getTokenSkipNewline(state);
  817. if (name === 'in' && state.token === '') {
  818. // end of expression -> this is the unit 'in' ('inch')
  819. node = new OperatorNode('*', 'multiply', [node, new SymbolNode('in')], true);
  820. } else {
  821. // operator 'a to b' or 'a in b'
  822. params = [node, parseRange(state)];
  823. node = new OperatorNode(name, fn, params);
  824. }
  825. }
  826. return node;
  827. }
  828. /**
  829. * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc
  830. * @return {Node} node
  831. * @private
  832. */
  833. function parseRange(state) {
  834. var node;
  835. var params = [];
  836. if (state.token === ':') {
  837. // implicit start=1 (one-based)
  838. node = new ConstantNode(1);
  839. } else {
  840. // explicit start
  841. node = parseAddSubtract(state);
  842. }
  843. if (state.token === ':' && state.conditionalLevel !== state.nestingLevel) {
  844. // we ignore the range operator when a conditional operator is being processed on the same level
  845. params.push(node);
  846. // parse step and end
  847. while (state.token === ':' && params.length < 3) {
  848. // eslint-disable-line no-unmodified-loop-condition
  849. getTokenSkipNewline(state);
  850. if (state.token === ')' || state.token === ']' || state.token === ',' || state.token === '') {
  851. // implicit end
  852. params.push(new SymbolNode('end'));
  853. } else {
  854. // explicit end
  855. params.push(parseAddSubtract(state));
  856. }
  857. }
  858. if (params.length === 3) {
  859. // params = [start, step, end]
  860. node = new RangeNode(params[0], params[2], params[1]); // start, end, step
  861. } else {
  862. // length === 2
  863. // params = [start, end]
  864. node = new RangeNode(params[0], params[1]); // start, end
  865. }
  866. }
  867. return node;
  868. }
  869. /**
  870. * add or subtract
  871. * @return {Node} node
  872. * @private
  873. */
  874. function parseAddSubtract(state) {
  875. var node, name, fn, params;
  876. node = parseMultiplyDivide(state);
  877. var operators = {
  878. '+': 'add',
  879. '-': 'subtract'
  880. };
  881. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  882. name = state.token;
  883. fn = operators[name];
  884. getTokenSkipNewline(state);
  885. var rightNode = parseMultiplyDivide(state);
  886. if (rightNode.isPercentage) {
  887. params = [node, new OperatorNode('*', 'multiply', [node, rightNode])];
  888. } else {
  889. params = [node, rightNode];
  890. }
  891. node = new OperatorNode(name, fn, params);
  892. }
  893. return node;
  894. }
  895. /**
  896. * multiply, divide, modulus
  897. * @return {Node} node
  898. * @private
  899. */
  900. function parseMultiplyDivide(state) {
  901. var node, last, name, fn;
  902. node = parseImplicitMultiplication(state);
  903. last = node;
  904. var operators = {
  905. '*': 'multiply',
  906. '.*': 'dotMultiply',
  907. '/': 'divide',
  908. './': 'dotDivide'
  909. };
  910. while (true) {
  911. if ((0, _object.hasOwnProperty)(operators, state.token)) {
  912. // explicit operators
  913. name = state.token;
  914. fn = operators[name];
  915. getTokenSkipNewline(state);
  916. last = parseImplicitMultiplication(state);
  917. node = new OperatorNode(name, fn, [node, last]);
  918. } else {
  919. break;
  920. }
  921. }
  922. return node;
  923. }
  924. /**
  925. * implicit multiplication
  926. * @return {Node} node
  927. * @private
  928. */
  929. function parseImplicitMultiplication(state) {
  930. var node, last;
  931. node = parseRule2(state);
  932. last = node;
  933. while (true) {
  934. if (state.tokenType === TOKENTYPE.SYMBOL || state.token === 'in' && (0, _is.isConstantNode)(node) || state.tokenType === TOKENTYPE.NUMBER && !(0, _is.isConstantNode)(last) && (!(0, _is.isOperatorNode)(last) || last.op === '!') || state.token === '(') {
  935. // parse implicit multiplication
  936. //
  937. // symbol: implicit multiplication like '2a', '(2+3)a', 'a b'
  938. // number: implicit multiplication like '(2+3)2'
  939. // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)'
  940. last = parseRule2(state);
  941. node = new OperatorNode('*', 'multiply', [node, last], true /* implicit */);
  942. } else {
  943. break;
  944. }
  945. }
  946. return node;
  947. }
  948. /**
  949. * Infamous "rule 2" as described in https://github.com/josdejong/mathjs/issues/792#issuecomment-361065370
  950. * And as amended in https://github.com/josdejong/mathjs/issues/2370#issuecomment-1054052164
  951. * Explicit division gets higher precedence than implicit multiplication
  952. * when the division matches this pattern:
  953. * [unaryPrefixOp]?[number] / [number] [symbol]
  954. * @return {Node} node
  955. * @private
  956. */
  957. function parseRule2(state) {
  958. var node = parsePercentage(state);
  959. var last = node;
  960. var tokenStates = [];
  961. while (true) {
  962. // Match the "number /" part of the pattern "number / number symbol"
  963. if (state.token === '/' && (0, _is.rule2Node)(last)) {
  964. // Look ahead to see if the next token is a number
  965. tokenStates.push((0, _extends2["default"])({}, state));
  966. getTokenSkipNewline(state);
  967. // Match the "number / number" part of the pattern
  968. if (state.tokenType === TOKENTYPE.NUMBER) {
  969. // Look ahead again
  970. tokenStates.push((0, _extends2["default"])({}, state));
  971. getTokenSkipNewline(state);
  972. // Match the "symbol" part of the pattern, or a left parenthesis
  973. if (state.tokenType === TOKENTYPE.SYMBOL || state.token === '(') {
  974. // We've matched the pattern "number / number symbol".
  975. // Rewind once and build the "number / number" node; the symbol will be consumed later
  976. (0, _extends2["default"])(state, tokenStates.pop());
  977. tokenStates.pop();
  978. last = parsePercentage(state);
  979. node = new OperatorNode('/', 'divide', [node, last]);
  980. } else {
  981. // Not a match, so rewind
  982. tokenStates.pop();
  983. (0, _extends2["default"])(state, tokenStates.pop());
  984. break;
  985. }
  986. } else {
  987. // Not a match, so rewind
  988. (0, _extends2["default"])(state, tokenStates.pop());
  989. break;
  990. }
  991. } else {
  992. break;
  993. }
  994. }
  995. return node;
  996. }
  997. /**
  998. * percentage or mod
  999. * @return {Node} node
  1000. * @private
  1001. */
  1002. function parsePercentage(state) {
  1003. var node, name, fn, params;
  1004. node = parseUnary(state);
  1005. var operators = {
  1006. '%': 'mod',
  1007. mod: 'mod'
  1008. };
  1009. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  1010. name = state.token;
  1011. fn = operators[name];
  1012. getTokenSkipNewline(state);
  1013. if (name === '%' && state.tokenType === TOKENTYPE.DELIMITER && state.token !== '(') {
  1014. // If the expression contains only %, then treat that as /100
  1015. node = new OperatorNode('/', 'divide', [node, new ConstantNode(100)], false, true);
  1016. } else {
  1017. params = [node, parseUnary(state)];
  1018. node = new OperatorNode(name, fn, params);
  1019. }
  1020. }
  1021. return node;
  1022. }
  1023. /**
  1024. * Unary plus and minus, and logical and bitwise not
  1025. * @return {Node} node
  1026. * @private
  1027. */
  1028. function parseUnary(state) {
  1029. var name, params, fn;
  1030. var operators = {
  1031. '-': 'unaryMinus',
  1032. '+': 'unaryPlus',
  1033. '~': 'bitNot',
  1034. not: 'not'
  1035. };
  1036. if ((0, _object.hasOwnProperty)(operators, state.token)) {
  1037. fn = operators[state.token];
  1038. name = state.token;
  1039. getTokenSkipNewline(state);
  1040. params = [parseUnary(state)];
  1041. return new OperatorNode(name, fn, params);
  1042. }
  1043. return parsePow(state);
  1044. }
  1045. /**
  1046. * power
  1047. * Note: power operator is right associative
  1048. * @return {Node} node
  1049. * @private
  1050. */
  1051. function parsePow(state) {
  1052. var node, name, fn, params;
  1053. node = parseLeftHandOperators(state);
  1054. if (state.token === '^' || state.token === '.^') {
  1055. name = state.token;
  1056. fn = name === '^' ? 'pow' : 'dotPow';
  1057. getTokenSkipNewline(state);
  1058. params = [node, parseUnary(state)]; // Go back to unary, we can have '2^-3'
  1059. node = new OperatorNode(name, fn, params);
  1060. }
  1061. return node;
  1062. }
  1063. /**
  1064. * Left hand operators: factorial x!, ctranspose x'
  1065. * @return {Node} node
  1066. * @private
  1067. */
  1068. function parseLeftHandOperators(state) {
  1069. var node, name, fn, params;
  1070. node = parseCustomNodes(state);
  1071. var operators = {
  1072. '!': 'factorial',
  1073. '\'': 'ctranspose'
  1074. };
  1075. while ((0, _object.hasOwnProperty)(operators, state.token)) {
  1076. name = state.token;
  1077. fn = operators[name];
  1078. getToken(state);
  1079. params = [node];
  1080. node = new OperatorNode(name, fn, params);
  1081. node = parseAccessors(state, node);
  1082. }
  1083. return node;
  1084. }
  1085. /**
  1086. * Parse a custom node handler. A node handler can be used to process
  1087. * nodes in a custom way, for example for handling a plot.
  1088. *
  1089. * A handler must be passed as second argument of the parse function.
  1090. * - must extend math.Node
  1091. * - must contain a function _compile(defs: Object) : string
  1092. * - must contain a function find(filter: Object) : Node[]
  1093. * - must contain a function toString() : string
  1094. * - the constructor is called with a single argument containing all parameters
  1095. *
  1096. * For example:
  1097. *
  1098. * nodes = {
  1099. * 'plot': PlotHandler
  1100. * }
  1101. *
  1102. * The constructor of the handler is called as:
  1103. *
  1104. * node = new PlotHandler(params)
  1105. *
  1106. * The handler will be invoked when evaluating an expression like:
  1107. *
  1108. * node = math.parse('plot(sin(x), x)', nodes)
  1109. *
  1110. * @return {Node} node
  1111. * @private
  1112. */
  1113. function parseCustomNodes(state) {
  1114. var params = [];
  1115. if (state.tokenType === TOKENTYPE.SYMBOL && (0, _object.hasOwnProperty)(state.extraNodes, state.token)) {
  1116. var CustomNode = state.extraNodes[state.token];
  1117. getToken(state);
  1118. // parse parameters
  1119. if (state.token === '(') {
  1120. params = [];
  1121. openParams(state);
  1122. getToken(state);
  1123. if (state.token !== ')') {
  1124. params.push(parseAssignment(state));
  1125. // parse a list with parameters
  1126. while (state.token === ',') {
  1127. // eslint-disable-line no-unmodified-loop-condition
  1128. getToken(state);
  1129. params.push(parseAssignment(state));
  1130. }
  1131. }
  1132. if (state.token !== ')') {
  1133. throw createSyntaxError(state, 'Parenthesis ) expected');
  1134. }
  1135. closeParams(state);
  1136. getToken(state);
  1137. }
  1138. // create a new custom node
  1139. // noinspection JSValidateTypes
  1140. return new CustomNode(params);
  1141. }
  1142. return parseSymbol(state);
  1143. }
  1144. /**
  1145. * parse symbols: functions, variables, constants, units
  1146. * @return {Node} node
  1147. * @private
  1148. */
  1149. function parseSymbol(state) {
  1150. var node, name;
  1151. if (state.tokenType === TOKENTYPE.SYMBOL || state.tokenType === TOKENTYPE.DELIMITER && state.token in NAMED_DELIMITERS) {
  1152. name = state.token;
  1153. getToken(state);
  1154. if ((0, _object.hasOwnProperty)(CONSTANTS, name)) {
  1155. // true, false, null, ...
  1156. node = new ConstantNode(CONSTANTS[name]);
  1157. } else if (NUMERIC_CONSTANTS.indexOf(name) !== -1) {
  1158. // NaN, Infinity
  1159. node = new ConstantNode(numeric(name, 'number'));
  1160. } else {
  1161. node = new SymbolNode(name);
  1162. }
  1163. // parse function parameters and matrix index
  1164. node = parseAccessors(state, node);
  1165. return node;
  1166. }
  1167. return parseDoubleQuotesString(state);
  1168. }
  1169. /**
  1170. * parse accessors:
  1171. * - function invocation in round brackets (...), for example sqrt(2)
  1172. * - index enclosed in square brackets [...], for example A[2,3]
  1173. * - dot notation for properties, like foo.bar
  1174. * @param {Object} state
  1175. * @param {Node} node Node on which to apply the parameters. If there
  1176. * are no parameters in the expression, the node
  1177. * itself is returned
  1178. * @param {string[]} [types] Filter the types of notations
  1179. * can be ['(', '[', '.']
  1180. * @return {Node} node
  1181. * @private
  1182. */
  1183. function parseAccessors(state, node, types) {
  1184. var params;
  1185. while ((state.token === '(' || state.token === '[' || state.token === '.') && (!types || types.indexOf(state.token) !== -1)) {
  1186. // eslint-disable-line no-unmodified-loop-condition
  1187. params = [];
  1188. if (state.token === '(') {
  1189. if ((0, _is.isSymbolNode)(node) || (0, _is.isAccessorNode)(node)) {
  1190. // function invocation like fn(2, 3) or obj.fn(2, 3)
  1191. openParams(state);
  1192. getToken(state);
  1193. if (state.token !== ')') {
  1194. params.push(parseAssignment(state));
  1195. // parse a list with parameters
  1196. while (state.token === ',') {
  1197. // eslint-disable-line no-unmodified-loop-condition
  1198. getToken(state);
  1199. params.push(parseAssignment(state));
  1200. }
  1201. }
  1202. if (state.token !== ')') {
  1203. throw createSyntaxError(state, 'Parenthesis ) expected');
  1204. }
  1205. closeParams(state);
  1206. getToken(state);
  1207. node = new FunctionNode(node, params);
  1208. } else {
  1209. // implicit multiplication like (2+3)(4+5) or sqrt(2)(1+2)
  1210. // don't parse it here but let it be handled by parseImplicitMultiplication
  1211. // with correct precedence
  1212. return node;
  1213. }
  1214. } else if (state.token === '[') {
  1215. // index notation like variable[2, 3]
  1216. openParams(state);
  1217. getToken(state);
  1218. if (state.token !== ']') {
  1219. params.push(parseAssignment(state));
  1220. // parse a list with parameters
  1221. while (state.token === ',') {
  1222. // eslint-disable-line no-unmodified-loop-condition
  1223. getToken(state);
  1224. params.push(parseAssignment(state));
  1225. }
  1226. }
  1227. if (state.token !== ']') {
  1228. throw createSyntaxError(state, 'Parenthesis ] expected');
  1229. }
  1230. closeParams(state);
  1231. getToken(state);
  1232. node = new AccessorNode(node, new IndexNode(params));
  1233. } else {
  1234. // dot notation like variable.prop
  1235. getToken(state);
  1236. if (state.tokenType !== TOKENTYPE.SYMBOL) {
  1237. throw createSyntaxError(state, 'Property name expected after dot');
  1238. }
  1239. params.push(new ConstantNode(state.token));
  1240. getToken(state);
  1241. var dotNotation = true;
  1242. node = new AccessorNode(node, new IndexNode(params, dotNotation));
  1243. }
  1244. }
  1245. return node;
  1246. }
  1247. /**
  1248. * Parse a double quotes string.
  1249. * @return {Node} node
  1250. * @private
  1251. */
  1252. function parseDoubleQuotesString(state) {
  1253. var node, str;
  1254. if (state.token === '"') {
  1255. str = parseDoubleQuotesStringToken(state);
  1256. // create constant
  1257. node = new ConstantNode(str);
  1258. // parse index parameters
  1259. node = parseAccessors(state, node);
  1260. return node;
  1261. }
  1262. return parseSingleQuotesString(state);
  1263. }
  1264. /**
  1265. * Parse a string surrounded by double quotes "..."
  1266. * @return {string}
  1267. */
  1268. function parseDoubleQuotesStringToken(state) {
  1269. var str = '';
  1270. while (currentCharacter(state) !== '' && currentCharacter(state) !== '"') {
  1271. if (currentCharacter(state) === '\\') {
  1272. // escape character, immediately process the next
  1273. // character to prevent stopping at a next '\"'
  1274. str += currentCharacter(state);
  1275. next(state);
  1276. }
  1277. str += currentCharacter(state);
  1278. next(state);
  1279. }
  1280. getToken(state);
  1281. if (state.token !== '"') {
  1282. throw createSyntaxError(state, 'End of string " expected');
  1283. }
  1284. getToken(state);
  1285. return JSON.parse('"' + str + '"'); // unescape escaped characters
  1286. }
  1287. /**
  1288. * Parse a single quotes string.
  1289. * @return {Node} node
  1290. * @private
  1291. */
  1292. function parseSingleQuotesString(state) {
  1293. var node, str;
  1294. if (state.token === '\'') {
  1295. str = parseSingleQuotesStringToken(state);
  1296. // create constant
  1297. node = new ConstantNode(str);
  1298. // parse index parameters
  1299. node = parseAccessors(state, node);
  1300. return node;
  1301. }
  1302. return parseMatrix(state);
  1303. }
  1304. /**
  1305. * Parse a string surrounded by single quotes '...'
  1306. * @return {string}
  1307. */
  1308. function parseSingleQuotesStringToken(state) {
  1309. var str = '';
  1310. while (currentCharacter(state) !== '' && currentCharacter(state) !== '\'') {
  1311. if (currentCharacter(state) === '\\') {
  1312. // escape character, immediately process the next
  1313. // character to prevent stopping at a next '\''
  1314. str += currentCharacter(state);
  1315. next(state);
  1316. }
  1317. str += currentCharacter(state);
  1318. next(state);
  1319. }
  1320. getToken(state);
  1321. if (state.token !== '\'') {
  1322. throw createSyntaxError(state, 'End of string \' expected');
  1323. }
  1324. getToken(state);
  1325. return JSON.parse('"' + str + '"'); // unescape escaped characters
  1326. }
  1327. /**
  1328. * parse the matrix
  1329. * @return {Node} node
  1330. * @private
  1331. */
  1332. function parseMatrix(state) {
  1333. var array, params, rows, cols;
  1334. if (state.token === '[') {
  1335. // matrix [...]
  1336. openParams(state);
  1337. getToken(state);
  1338. if (state.token !== ']') {
  1339. // this is a non-empty matrix
  1340. var row = parseRow(state);
  1341. if (state.token === ';') {
  1342. // 2 dimensional array
  1343. rows = 1;
  1344. params = [row];
  1345. // the rows of the matrix are separated by dot-comma's
  1346. while (state.token === ';') {
  1347. // eslint-disable-line no-unmodified-loop-condition
  1348. getToken(state);
  1349. params[rows] = parseRow(state);
  1350. rows++;
  1351. }
  1352. if (state.token !== ']') {
  1353. throw createSyntaxError(state, 'End of matrix ] expected');
  1354. }
  1355. closeParams(state);
  1356. getToken(state);
  1357. // check if the number of columns matches in all rows
  1358. cols = params[0].items.length;
  1359. for (var r = 1; r < rows; r++) {
  1360. if (params[r].items.length !== cols) {
  1361. throw createError(state, 'Column dimensions mismatch ' + '(' + params[r].items.length + ' !== ' + cols + ')');
  1362. }
  1363. }
  1364. array = new ArrayNode(params);
  1365. } else {
  1366. // 1 dimensional vector
  1367. if (state.token !== ']') {
  1368. throw createSyntaxError(state, 'End of matrix ] expected');
  1369. }
  1370. closeParams(state);
  1371. getToken(state);
  1372. array = row;
  1373. }
  1374. } else {
  1375. // this is an empty matrix "[ ]"
  1376. closeParams(state);
  1377. getToken(state);
  1378. array = new ArrayNode([]);
  1379. }
  1380. return parseAccessors(state, array);
  1381. }
  1382. return parseObject(state);
  1383. }
  1384. /**
  1385. * Parse a single comma-separated row from a matrix, like 'a, b, c'
  1386. * @return {ArrayNode} node
  1387. */
  1388. function parseRow(state) {
  1389. var params = [parseAssignment(state)];
  1390. var len = 1;
  1391. while (state.token === ',') {
  1392. // eslint-disable-line no-unmodified-loop-condition
  1393. getToken(state);
  1394. // parse expression
  1395. params[len] = parseAssignment(state);
  1396. len++;
  1397. }
  1398. return new ArrayNode(params);
  1399. }
  1400. /**
  1401. * parse an object, enclosed in angle brackets{...}, for example {value: 2}
  1402. * @return {Node} node
  1403. * @private
  1404. */
  1405. function parseObject(state) {
  1406. if (state.token === '{') {
  1407. openParams(state);
  1408. var key;
  1409. var properties = {};
  1410. do {
  1411. getToken(state);
  1412. if (state.token !== '}') {
  1413. // parse key
  1414. if (state.token === '"') {
  1415. key = parseDoubleQuotesStringToken(state);
  1416. } else if (state.token === '\'') {
  1417. key = parseSingleQuotesStringToken(state);
  1418. } else if (state.tokenType === TOKENTYPE.SYMBOL || state.tokenType === TOKENTYPE.DELIMITER && state.token in NAMED_DELIMITERS) {
  1419. key = state.token;
  1420. getToken(state);
  1421. } else {
  1422. throw createSyntaxError(state, 'Symbol or string expected as object key');
  1423. }
  1424. // parse key/value separator
  1425. if (state.token !== ':') {
  1426. throw createSyntaxError(state, 'Colon : expected after object key');
  1427. }
  1428. getToken(state);
  1429. // parse key
  1430. properties[key] = parseAssignment(state);
  1431. }
  1432. } while (state.token === ','); // eslint-disable-line no-unmodified-loop-condition
  1433. if (state.token !== '}') {
  1434. throw createSyntaxError(state, 'Comma , or bracket } expected after object value');
  1435. }
  1436. closeParams(state);
  1437. getToken(state);
  1438. var node = new ObjectNode(properties);
  1439. // parse index parameters
  1440. node = parseAccessors(state, node);
  1441. return node;
  1442. }
  1443. return parseNumber(state);
  1444. }
  1445. /**
  1446. * parse a number
  1447. * @return {Node} node
  1448. * @private
  1449. */
  1450. function parseNumber(state) {
  1451. var numberStr;
  1452. if (state.tokenType === TOKENTYPE.NUMBER) {
  1453. // this is a number
  1454. numberStr = state.token;
  1455. getToken(state);
  1456. return new ConstantNode(numeric(numberStr, config.number));
  1457. }
  1458. return parseParentheses(state);
  1459. }
  1460. /**
  1461. * parentheses
  1462. * @return {Node} node
  1463. * @private
  1464. */
  1465. function parseParentheses(state) {
  1466. var node;
  1467. // check if it is a parenthesized expression
  1468. if (state.token === '(') {
  1469. // parentheses (...)
  1470. openParams(state);
  1471. getToken(state);
  1472. node = parseAssignment(state); // start again
  1473. if (state.token !== ')') {
  1474. throw createSyntaxError(state, 'Parenthesis ) expected');
  1475. }
  1476. closeParams(state);
  1477. getToken(state);
  1478. node = new ParenthesisNode(node);
  1479. node = parseAccessors(state, node);
  1480. return node;
  1481. }
  1482. return parseEnd(state);
  1483. }
  1484. /**
  1485. * Evaluated when the expression is not yet ended but expected to end
  1486. * @return {Node} res
  1487. * @private
  1488. */
  1489. function parseEnd(state) {
  1490. if (state.token === '') {
  1491. // syntax error or unexpected end of expression
  1492. throw createSyntaxError(state, 'Unexpected end of expression');
  1493. } else {
  1494. throw createSyntaxError(state, 'Value expected');
  1495. }
  1496. }
  1497. /**
  1498. * Shortcut for getting the current row value (one based)
  1499. * Returns the line of the currently handled expression
  1500. * @private
  1501. */
  1502. /* TODO: implement keeping track on the row number
  1503. function row () {
  1504. return null
  1505. }
  1506. */
  1507. /**
  1508. * Shortcut for getting the current col value (one based)
  1509. * Returns the column (position) where the last state.token starts
  1510. * @private
  1511. */
  1512. function col(state) {
  1513. return state.index - state.token.length + 1;
  1514. }
  1515. /**
  1516. * Create an error
  1517. * @param {Object} state
  1518. * @param {string} message
  1519. * @return {SyntaxError} instantiated error
  1520. * @private
  1521. */
  1522. function createSyntaxError(state, message) {
  1523. var c = col(state);
  1524. var error = new SyntaxError(message + ' (char ' + c + ')');
  1525. error["char"] = c;
  1526. return error;
  1527. }
  1528. /**
  1529. * Create an error
  1530. * @param {Object} state
  1531. * @param {string} message
  1532. * @return {Error} instantiated error
  1533. * @private
  1534. */
  1535. function createError(state, message) {
  1536. var c = col(state);
  1537. var error = new SyntaxError(message + ' (char ' + c + ')');
  1538. error["char"] = c;
  1539. return error;
  1540. }
  1541. // Now that we can parse, automatically convert strings to Nodes by parsing
  1542. typed.addConversion({
  1543. from: 'string',
  1544. to: 'Node',
  1545. convert: parse
  1546. });
  1547. return parse;
  1548. });
  1549. exports.createParse = createParse;