parser.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. 'use strict';
  2. class ParserError extends Error {}
  3. function parser_error (element, info) {
  4. check(parser_error, arguments, {
  5. element: Any, // $u(Token.Valid, SyntaxTreeNode),
  6. info: Str
  7. })
  8. function get_message () {
  9. function get_token (tree) {
  10. assert(is_not(tree, SyntaxTreeEmpty))
  11. return transform(tree, [
  12. { when_it_is: SyntaxTreeLeaf, use: t => t.children },
  13. { when_it_is: Otherwise, use: t => get_token(t.children[0]) }
  14. ])
  15. }
  16. let token = transform(element, [
  17. { when_it_is: Token.Valid, use: x => x },
  18. { when_it_is: Otherwise, use: x => get_token(x) }
  19. ])
  20. let { row, col } = token.position
  21. return `row ${row}, column ${col}: '${token.matched.name}': ${info}`
  22. }
  23. return {
  24. assert: function (condition) {
  25. this.if(!condition)
  26. },
  27. if: function (condition) {
  28. if (condition) { this.throw() }
  29. },
  30. throw: function () {
  31. throw ( new ParserError(get_message()) )
  32. }
  33. }
  34. }
  35. function get_tokens (string) {
  36. check(get_tokens, arguments, { string: Str })
  37. function check_parentheses (tokens) {
  38. let union = (...list) => $u.apply({}, map(list, x => Token(x)))
  39. let right_of = {
  40. '(' : ')', '[' : ']', '{' : '}', '.[': ']', '.{' : '}',
  41. '..[': ']', '..{': '}', '...{': '}'
  42. }
  43. let left = union('(', '[', '{', '.[', '.{', '..[', '..{', '...{')
  44. let right = union(')', ']', '}')
  45. let all = $u(left, right)
  46. let parentheses = filter_lazy(tokens, token => is(token, all))
  47. function top (stack) {
  48. assert(stack.length > 0)
  49. return stack[stack.length-1]
  50. }
  51. function check_error (stack) {
  52. let msg = 'missing coressponding parentheses'
  53. if (stack.length > 0) {
  54. parser_error(top(stack).token, msg).throw()
  55. }
  56. }
  57. check_error(fold(parentheses, [], function (token, stack) {
  58. let name = token.matched.name
  59. let pos = token.position
  60. let element = { name: name, pos: pos, token: token }
  61. let pushed = added(stack, element)
  62. let poped = stack.slice(0, stack.length-1)
  63. let empty = $(stack => stack.length == 0)
  64. let corresponding = $(stack => right_of[top(stack).name] == name)
  65. return transform(token, [
  66. { when_it_is: left, use: t => pushed },
  67. { when_it_is: right, use: t => transform(stack, [
  68. { when_it_is: empty, use: s => BreakWith(pushed) },
  69. { when_it_is: corresponding, use: s => poped },
  70. { when_it_is: Otherwise, use: s => Break }
  71. ])}
  72. ])
  73. }))
  74. }
  75. function assert_valid (tokens) {
  76. return map_lazy(tokens, t => (assert(is(t, Token.Valid)) && t))
  77. }
  78. function remove_comment (tokens) {
  79. /* remove ordinary comment and inline comment */
  80. let Current = name => $(look => is(look.current, Token(name)))
  81. let Left = name => $(look => is(look.left, Token(name)))
  82. let InlineCommentElement = $u(
  83. Current('..'),
  84. $n(Left('..'), Current('Name'))
  85. )
  86. return apply_on(tokens, chain(
  87. x => filter_lazy(x, t => is_not(t, Token('Comment'))),
  88. x => lookaside(x, Token.Null),
  89. x => filter_lazy(x, look => is_not(look, InlineCommentElement)),
  90. x => map_lazy(x, look => look.current)
  91. ))
  92. }
  93. function remove_space (tokens) {
  94. /**
  95. * note: linefeed won't be removed by this function.
  96. * therefore, the effect of add_call_operator()
  97. * and add_get_operator() cannot cross lines.
  98. */
  99. return filter_lazy(tokens, token => token.matched.name != 'Space')
  100. }
  101. function add_call_operator (tokens) {
  102. return insert(tokens, Token.Null, function (token, next) {
  103. let this_is_id = is(token, Token('Name'))
  104. let this_is_rp = is(token, Token(')'))
  105. let next_is_lp = is(next, Token('('))
  106. let need_insert = (this_is_id || this_is_rp) && next_is_lp
  107. return (
  108. need_insert?
  109. Token.create_from(token, 'Operator', 'Call', '@'): Nothing
  110. )
  111. })
  112. }
  113. function add_get_operator (tokens) {
  114. return insert(tokens, Token.Null, function (token, next) {
  115. let this_is_id = is(token, Token('Name'))
  116. let next_is_lb = is(next, Token('['))
  117. let need_insert = (this_is_id && next_is_lb)
  118. return (
  119. need_insert?
  120. Token.create_from(token, 'Operator', 'Get', '#'): Nothing
  121. )
  122. })
  123. }
  124. function eliminate_ambiguity (name) {
  125. let mapper = ({
  126. '.': function (left, token, right) {
  127. let par = $u(Token(')'), Token(']'), Token('}'))
  128. let left_is_op = is(left, $d(Token.Operator, par))
  129. let left_is_lf = is(left, Token('Linefeed'))
  130. let name = (left_is_op || left_is_lf)? 'Parameter': 'Access'
  131. return Token.create_from(token, 'Operator', name)
  132. },
  133. Name: function (left, token, right) {
  134. let left_is_access = is(left, Token('Access'))
  135. let name = left_is_access? 'Member': 'Identifier'
  136. return Token.create_from(token, 'Name', name)
  137. }
  138. })[name]
  139. return function (tokens) {
  140. function transform (item) {
  141. let { left, current, right } = item
  142. let token = current
  143. let current_name = token.matched.name
  144. return (name == current_name)?
  145. mapper(left, token, right): token
  146. }
  147. return map_lazy(lookaside(tokens, Token.Null), transform)
  148. }
  149. }
  150. function remove_linefeed (tokens) {
  151. return filter_lazy(tokens, token => token.matched.name != 'Linefeed')
  152. }
  153. let raw = list(CodeScanner(string).match(Matcher(Tokens)))
  154. check_parentheses(assert_valid(raw))
  155. return apply_on(raw, chain(
  156. remove_comment,
  157. remove_space,
  158. add_call_operator,
  159. add_get_operator,
  160. eliminate_ambiguity('.'),
  161. eliminate_ambiguity('Name'),
  162. remove_linefeed,
  163. assert_valid,
  164. list
  165. ))
  166. }
  167. const SyntaxTreeEmpty = Struct({
  168. name: Str,
  169. children: $n(List, $(a => a.length == 0))
  170. })
  171. const SyntaxTreeLeaf = Struct({
  172. name: Str,
  173. children: Token.Valid
  174. })
  175. const SyntaxTreeNode = $u(SyntaxTreeLeaf, Struct({
  176. name: Str,
  177. children: ListOf( $u(SyntaxTreeLeaf, $(x => is(x, SyntaxTreeNode))) )
  178. }))
  179. const SyntaxTreeRoot = $n(SyntaxTreeNode, Struct({
  180. ok: Bool,
  181. amount: Int
  182. }))
  183. function print_tree (tree, deepth = 0, is_last = [true]) {
  184. let indent_increment = 2
  185. let repeat = function (string, n, f = (i => '')) {
  186. return join(map_lazy(count(n), i => f(i) || string), '')
  187. }
  188. let base = repeat(' ', indent_increment)
  189. let indent = repeat(base, deepth,
  190. i => (
  191. is_last[i]?
  192. repeat(' ', indent_increment):
  193. ('│'+repeat(' ', indent_increment-1))
  194. )
  195. )
  196. let pointer = (
  197. ((is_last[deepth])? '└': '├')
  198. + repeat('─', indent_increment-1)
  199. + ((tree.children.length > 0)? '┬': '─')
  200. + '─'
  201. )
  202. let node_name = (
  203. is(tree.time, Num)?
  204. `${tree.name} (${tree.time.toFixed(0)})`:
  205. `${tree.name}`
  206. )
  207. let node_children = transform(tree, [
  208. { when_it_is: SyntaxTreeEmpty, use: t => (' ' + '[]') },
  209. { when_it_is: SyntaxTreeLeaf, use: function (tree) {
  210. let string = tree.children.matched.string
  211. return (string == tree.name)? '': `: ${string}`
  212. } },
  213. { when_it_is: Otherwise, use: function (tree) {
  214. let last_index = tree.children.length-1
  215. let subtree_string = apply_on(tree.children, chain(
  216. x => map_lazy(x, (child, index) => print_tree(
  217. child, deepth+1,
  218. added(is_last, index == last_index)
  219. )),
  220. x => join(x, LF)
  221. ))
  222. return (LF + subtree_string)
  223. } }
  224. ])
  225. return (indent + pointer + node_name + node_children)
  226. }
  227. function build_leaf (token) {
  228. check(build_leaf, arguments, { token: Token.Valid })
  229. return { amount: 1, name: token.matched.name, children: token }
  230. }
  231. function wipe_list(list) {
  232. while(list.length > 0) {
  233. list.pop()
  234. }
  235. }
  236. function copy_list(dest, source) {
  237. for(let element of source) {
  238. dest.push(element)
  239. }
  240. }
  241. let f_count = count
  242. function match_part (syntax, part_list, tokens, part_name, pos) {
  243. let N = 32
  244. let buffer = new Int32Array(new ArrayBuffer(10000*N*4))
  245. let saved = new Int32Array(new ArrayBuffer(100000*N*4))
  246. let names = list(cat([null], part_list))
  247. let id_of_name = fold(names, {}, (e,v,i) => (v[e]=i, v))
  248. let key = {
  249. name: 0,
  250. amount: 1,
  251. parent: 2,
  252. pos: 3,
  253. deriv: 4,
  254. n: 5,
  255. }
  256. let offset = 6
  257. let cur = 0
  258. let count = 0
  259. function watch() {
  260. let l = []
  261. for(let i=0; i<=cur; i++) {
  262. l.push({
  263. name: names[buffer[i*N + key.name]],
  264. amount: buffer[i*N + key.amount],
  265. parent: buffer[i*N + key.parent],
  266. pos: buffer[i*N + key.pos],
  267. deriv: buffer[i*N + key.deriv],
  268. children: map(f_count(buffer[i*N + key.n]), j => buffer[i*N + offset + j])
  269. })
  270. }
  271. return l
  272. }
  273. /*
  274. function push(name, parent) {
  275. cur += 1
  276. let top = N*(cur)
  277. buffer[top + key.name] = id_of_name[name]
  278. buffer[top + key.amount] = 0
  279. buffer[top + key.parent] = parent
  280. buffer[top + key.pos] = -1
  281. buffer[top + key.deriv] = 0
  282. buffer[top + key.n] = 0
  283. }
  284. function pop() {
  285. let top = N*cur
  286. let parent = N*buffer[top + key.parent]
  287. if (top != 0) {
  288. buffer[parent + key.amount] += buffer[top + key.amount]
  289. buffer[parent + offset + buffer[parent + key.n]] = count
  290. buffer[parent + key.n] += 1
  291. }
  292. let new_saved = N*count
  293. saved[new_saved + key.name] = buffer[top + key.name]
  294. saved[new_saved + key.amount] = buffer[top + key.amount]
  295. saved[new_saved + key.n] = buffer[top + key.n]
  296. let i = 0
  297. while(i < buffer[top + key.n]) {
  298. saved[new_saved + offset + i] = buffer[top + offset + i]
  299. i++
  300. }
  301. count += 1
  302. cur -= 1
  303. }
  304. function rollback() {
  305. let i_parent = buffer[N*cur + key.parent]
  306. buffer[N*i_parent + key.deriv] += 1
  307. cur = i_parent
  308. }
  309. */
  310. buffer[N*0 + key.name] = 0
  311. buffer[key.amount] = 0
  312. buffer[key.parent] = -1
  313. buffer[key.pos] = pos
  314. buffer[key.deriv] = 0
  315. buffer[key.n] = 0
  316. cur += 1
  317. buffer[N*cur + key.name] = id_of_name[part_name]
  318. buffer[N + key.amount] = 0
  319. buffer[N + key.parent] = 0
  320. buffer[N + key.pos] = pos
  321. buffer[N + key.deriv] = 0
  322. buffer[N + key.n] = 0
  323. let i = 0
  324. while (cur > 0) {
  325. var top = N * cur
  326. var parent = N * buffer[top + key.parent]
  327. var pos = buffer[top + key.pos]
  328. if (pos == -1) {
  329. pos = buffer[parent + key.pos] + buffer[parent + key.amount]
  330. buffer[top + key.pos] = pos
  331. }
  332. //var token = (pos < tokens.length)? tokens[pos]: Token.Null
  333. //var part = names[buffer[top + key.name]]
  334. assert(names[buffer[top + key.name]] != null)
  335. var item = (syntax[names[buffer[top + key.name]]])
  336. var deriv = buffer[top + key.deriv]
  337. if (typeof item != 'undefined') {
  338. assert(typeof item.derivations != 'undefined')
  339. if (deriv < item.derivations.length) {
  340. if (buffer[top + key.n] == item.derivations[deriv].length) {
  341. // pop
  342. buffer[parent + key.amount] += buffer[top + key.amount]
  343. buffer[parent + offset + buffer[parent + key.n]] = count
  344. buffer[parent + key.n] += 1
  345. var new_saved = N*count
  346. saved[new_saved + key.name] = buffer[top + key.name]
  347. saved[new_saved + key.amount] = buffer[top + key.amount]
  348. saved[new_saved + key.n] = buffer[top + key.n]
  349. var j = 0
  350. while(j < buffer[top + key.n]) {
  351. saved[new_saved + offset + j] = (
  352. buffer[top + offset + j]
  353. )
  354. j++
  355. }
  356. count += 1
  357. cur -= 1
  358. } else {
  359. buffer[top + key.n] = 0
  360. buffer[top + key.amount] = 0
  361. var d = item.derivations[deriv]
  362. if (d.length > 0) {
  363. var push_parent = cur
  364. var k = 0
  365. while (k < d.length) {
  366. // push(part: d[k], parent: push_parent)
  367. var new_top = top + N*(k+1)
  368. buffer[new_top + key.name] = (
  369. id_of_name[d[d.length-k-1]]
  370. )
  371. buffer[new_top + key.amount] = 0
  372. buffer[new_top + key.parent] = push_parent
  373. buffer[new_top + key.pos] = -1
  374. buffer[new_top + key.deriv] = 0
  375. buffer[new_top + key.n] = 0
  376. k++
  377. }
  378. cur += d.length
  379. } else {
  380. // pop
  381. buffer[parent + key.amount] += buffer[top + key.amount]
  382. buffer[parent + offset + buffer[parent + key.n]] = count
  383. buffer[parent + key.n] += 1
  384. var new_saved = N*count
  385. saved[new_saved + key.name] = buffer[top + key.name]
  386. saved[new_saved + key.amount] = buffer[top + key.amount]
  387. saved[new_saved + key.n] = buffer[top + key.n]
  388. var j = 0
  389. while(j < buffer[top + key.n]) {
  390. saved[new_saved + offset + j] = (
  391. buffer[top + offset + j]
  392. )
  393. j++
  394. }
  395. count += 1
  396. cur -= 1
  397. }
  398. }
  399. } else {
  400. // rollback
  401. buffer[parent + key.deriv] += 1
  402. cur = buffer[top + key.parent]
  403. }
  404. } else if ((names[buffer[top + key.name]])[0] == '~') {
  405. var kw_ok = false
  406. if (pos < tokens.length) {
  407. kw_ok = true
  408. var u = 1
  409. while (u < (names[buffer[top + key.name]]).length) {
  410. kw_ok = kw_ok && ((names[buffer[top + key.name]])[u] == tokens[pos].matched.string[u-1])
  411. if (!kw_ok) { break }
  412. u++
  413. }
  414. }
  415. if (kw_ok) {
  416. // pop token
  417. buffer[parent + key.amount] += 1
  418. buffer[parent + offset + buffer[parent + key.n]] = -pos
  419. buffer[parent + key.n] += 1
  420. cur -= 1
  421. } else {
  422. // rollback
  423. buffer[parent + key.deriv] += 1
  424. cur = buffer[top + key.parent]
  425. }
  426. } else if (pos < tokens.length && tokens[pos].matched.name == names[buffer[top + key.name]]) {
  427. // pop token
  428. buffer[parent + key.amount] += 1
  429. buffer[parent + offset + buffer[parent + key.n]] = -pos
  430. buffer[parent + key.n] += 1
  431. cur -= 1
  432. } else {
  433. // rollback
  434. buffer[parent + key.deriv] += 1
  435. cur = buffer[top + key.parent]
  436. }
  437. i++
  438. //console.log(i, cur, watch())
  439. }
  440. return { count: count, array: saved }
  441. }
  442. function match_part1 (syntax, tokens, part_name, pos) {
  443. let t_enter = performance.now()
  444. let output = []
  445. let stack = [{
  446. tree: {
  447. name: '[root]',
  448. children: [],
  449. amount: 0
  450. },
  451. pos: pos,
  452. parent: -1,
  453. deriv_index: 0
  454. }]
  455. let cur = 0
  456. let count = 0
  457. for (let i=0; i<10000; i++) {
  458. output.push([])
  459. }
  460. for (let i=0; i<1000; i++) {
  461. stack.push({
  462. tree: {
  463. name: null,
  464. children: [],
  465. amount: -1
  466. },
  467. pos: -1,
  468. parent: -1,
  469. deriv_index: -1
  470. })
  471. }
  472. function push(name, parent) {
  473. let top = stack[++cur]
  474. top.tree.name = name
  475. wipe_list(top.tree.children)
  476. top.tree.amount = 0
  477. top.parent = parent
  478. top.deriv_index = 0
  479. top.push_time = performance.now()
  480. }
  481. function pop() {
  482. let top = stack[cur]
  483. stack[top.parent].tree.amount += top.tree.amount
  484. stack[top.parent].tree.children.push(count)
  485. copy_list(output[count], top.tree.children)
  486. count++
  487. wipe_list(top.tree.children)
  488. /*
  489. stack[top.parent].tree.children.push({
  490. name: top.tree.name,
  491. amount: top.tree.amount,
  492. children: top.tree.children,
  493. time: (performance.now() - top.push_time)
  494. })
  495. */
  496. cur--
  497. }
  498. function rollback() {
  499. let top = stack[cur]
  500. stack[top.parent].deriv_index++
  501. cur = top.parent
  502. }
  503. push(part_name, 0)
  504. let i = 0
  505. let max = 0
  506. while (cur > 0) {
  507. let top = stack[cur]
  508. if (top.parent >= 0) {
  509. top.pos = stack[top.parent].pos + stack[top.parent].tree.amount
  510. }
  511. let token = (top.pos < tokens.length)? tokens[top.pos]: Token.Null
  512. let part = top.tree.name
  513. if (has(syntax, part)) {
  514. let item = syntax[part]
  515. if (typeof item == 'function') {
  516. let match = (item())(syntax, tokens, top.pos)
  517. if (match != null) {
  518. assert(false)
  519. top.tree.amount = match.amount
  520. top.tree.children = match.children
  521. pop()
  522. } else {
  523. rollback()
  524. }
  525. } else {
  526. let derivations = item.derivations
  527. if (top.deriv_index < derivations.length) {
  528. let built = top.tree.children.length
  529. let required = derivations[top.deriv_index].length
  530. if (built == required) {
  531. pop()
  532. } else {
  533. wipe_list(top.tree.children)
  534. top.tree.amount = 0
  535. let d = derivations[top.deriv_index]
  536. if (d.length > 0) {
  537. let parent = cur
  538. for (let part of rev(d)) {
  539. push(part, parent)
  540. }
  541. } else {
  542. pop()
  543. }
  544. }
  545. } else {
  546. rollback()
  547. }
  548. }
  549. } else if (part.startsWith('~')) {
  550. let keyword = part.slice(1, part.length)
  551. if (token != Token.Null && token.matched.string == keyword) {
  552. top.tree.name = 'Keyword'
  553. top.tree.amount = 1
  554. top.tree.children.push(token)
  555. pop()
  556. } else {
  557. rollback()
  558. }
  559. } else if (token != Token.Null && token.matched.name == part) {
  560. top.tree.amount = 1
  561. top.tree.children.push(token)
  562. pop()
  563. } else {
  564. rollback()
  565. }
  566. if (cur > max) { max = cur }
  567. i++
  568. //console.log(i++, cur, RawCompound(Clone(CookCompound(stack.slice(0,11)))))
  569. }
  570. console.log("max", max)
  571. console.log("loop", i)
  572. console.log("out-time", performance.now()-t_enter)
  573. /*
  574. let root = stack[0]
  575. if (root.tree.children.length > 0) {
  576. return root.tree.children[0]
  577. } else {
  578. return null
  579. }*/
  580. return { count: count, output: output }
  581. }
  582. // DFS
  583. function match_item (syntax, tokens, item_name, pos) {
  584. let item = syntax[item_name]
  585. if (is(item, Fun)) {
  586. let t0 = performance.now()
  587. let match = (item())(syntax, tokens, pos)
  588. let t1 = performance.now()
  589. if (match != null) {
  590. match.name = item_name
  591. match.time = t1-t0
  592. return match
  593. }
  594. } else if(has(item, 'derivations')) {
  595. for (let i=0; i<item.derivations.length; i++) {
  596. let d = item.derivations[i]
  597. let t0 = performance.now()
  598. let match = null
  599. let amount = 0
  600. let children = []
  601. let failed = false
  602. for (let i=0; i<d.length; i++) {
  603. let part = d[i]
  604. let p = pos + amount
  605. let token = (p < tokens.length)? tokens[p]: Token.Null
  606. let i_match = null
  607. if (has(syntax, part)) {
  608. i_match = match_item(syntax, tokens, part, p)
  609. } else if (part.startsWith('~')) {
  610. let keyword = part.slice(1, part.length)
  611. let valid = is(token, Token('Identifier'))
  612. if (valid && token.matched.string == keyword) {
  613. i_match = {
  614. amount: 1,
  615. name: 'Keyword',
  616. children: token
  617. }
  618. }
  619. } else {
  620. if (is(token, Token(part))) {
  621. i_match = {
  622. amount: 1,
  623. name: part, children: token
  624. }
  625. }
  626. }
  627. if (i_match != null) {
  628. amount += i_match.amount
  629. children.push(i_match)
  630. } else {
  631. failed = true
  632. break
  633. }
  634. }
  635. match = failed? null: { amount: amount, children: children }
  636. let t1 = performance.now()
  637. if (match != null) {
  638. match.name = item_name
  639. match.time = t1-t0
  640. return match
  641. }
  642. }
  643. return null
  644. } else {
  645. assert(false)
  646. }
  647. }
  648. function build_tree (syntax, root, tokens, pos = 0) {
  649. let match = match_part(syntax, PartList, tokens, root, pos)
  650. //assert(is(match, SyntaxTreeRoot))
  651. // TODO: check amount
  652. return match
  653. //return (match != null)? match: { ok: false, amount: 0 }
  654. }
  655. function parse_simple (syntax, tokens, pos) {
  656. /**
  657. * parse simple experssion using shunting yard algorithm
  658. *
  659. * 1. invoke converge() to parse argument list and key expression
  660. * 2. define operations on output & operator stack
  661. * 3. run the shunting yard algorithm
  662. * 4. get final state of stacks and return result
  663. */
  664. function* converge () {
  665. let offset = 0
  666. while (pos+offset < tokens.length) {
  667. let p = pos + offset
  668. let token = tokens[p]
  669. let left = (p-1 >= 0)? tokens[p-1]: Token.Null
  670. let is_args = ( is(token, Token('(')) && is(left, Token('Call')) )
  671. let is_key = ( is(token, Token('[')) && is(left, Token('Get')) )
  672. let is_par = ( is(token, Token('(')) && is_not(left, Token('Call')) )
  673. if ( is_args || is_key ) {
  674. let type = is_args? 'args': 'key'
  675. let syntax_item = (
  676. { args: 'ArgList', key: 'Key' }
  677. )[type]
  678. let err_msg = (
  679. { args: 'bad argument list', key: 'bad key' }
  680. )[type]
  681. let match = build_tree(syntax, syntax_item, tokens, p)
  682. let err = parser_error(token, err_msg)
  683. err.assert(match != null)
  684. yield match
  685. offset += match.amount
  686. } else if ( is_par ) {
  687. let syntax_item = 'Wrapped'
  688. let err_msg = 'missing )'
  689. let match = build_tree(syntax, syntax_item, tokens, p)
  690. let err = parser_error(token, err_msg)
  691. err.assert(match != null)
  692. yield match
  693. offset += match.amount
  694. } else {
  695. let left_is_operand = is(left, $u(SimpleOperand, Token(')')))
  696. let this_is_operand = is(token, $u(SimpleOperand, Token('(')))
  697. if ( left_is_operand && this_is_operand && offset > 0 ) {
  698. break
  699. } else {
  700. yield build_leaf(token)
  701. offset += 1
  702. }
  703. }
  704. }
  705. }
  706. let sentinel = {
  707. position: { row: -1, col: -1 },
  708. matched: { category: 'Operator', name: 'Sentinel', string: '' }
  709. }
  710. let input = cat(converge(), [{ name: 'Sentinel', children: sentinel }])
  711. let info = (operator => SimpleOperator[operator.matched.name])
  712. function empty (state) {
  713. let operators = state.operators
  714. return operators.length == 0
  715. }
  716. function top (state) {
  717. let operators = state.operators
  718. assert(operators.length > 0)
  719. return operators[operators.length-1]
  720. }
  721. function pop (state) {
  722. let operators = state.operators
  723. let output = state.output
  724. let operator = top(state)
  725. let err_op = parser_error(operator, 'missing operand')
  726. let type = info(operator).type
  727. let count = ({ prefix: 1, infix: 2 })[type]
  728. err_op.assert(output.length >= count)
  729. let take_out = output.slice(output.length-count, output.length)
  730. let remaining = output.slice(0, output.length-count)
  731. let poped = operators.slice(0, operators.length-1)
  732. let children = added_front(take_out, build_leaf(operator))
  733. let err_arg_msg = 'argument list involved in non-call expression'
  734. let err_arg = parser_error(operator, err_arg_msg)
  735. err_arg.if(
  736. is_not(operator, Token('Call'))
  737. && exists(children, operand => operand.name == 'ArgList')
  738. )
  739. let reduced = {
  740. name: 'SimpleUnit',
  741. children: children,
  742. amount: fold(children, 0, (tree, sum) => sum+tree.amount)
  743. }
  744. return {
  745. output: added(remaining, reduced),
  746. operators: poped
  747. }
  748. }
  749. function push (state, operator) {
  750. let operators = state.operators
  751. let output = state.output
  752. return {
  753. output: output,
  754. operators: added(operators, operator)
  755. }
  756. }
  757. function append (state, operand) {
  758. let operators = state.operators
  759. let output = state.output
  760. let element = is(operand, Token)? build_leaf(operand): operand
  761. return {
  762. output: added(output, element),
  763. operators: operators
  764. }
  765. }
  766. function put (state, operator) {
  767. let operators = state.operators
  768. let output = state.output
  769. return (empty(state))? push(state, operator): (function() {
  770. let input = operator
  771. let stack = top(state)
  772. let input_info = info(input)
  773. let stack_info = info(stack)
  774. let assoc = input_info.assoc
  775. let should_pop = ({
  776. left: input_info.priority <= stack_info.priority,
  777. right: input_info.priority < stack_info.priority
  778. })[assoc]
  779. return should_pop? put(pop(state), operator): push(state, input)
  780. })()
  781. }
  782. function get_result (state) {
  783. let operators = state.operators
  784. let output = state.output
  785. let output_first = output[0] || null
  786. let err = parser_error(output_first, 'missing operator')
  787. err.if(output.length > 1) // 1 = final result
  788. assert(output.length == 1 && operators.length == 1)
  789. return output_first
  790. }
  791. let initial = { output: [], operators: [] }
  792. let final = fold(input, initial, function (element, state) {
  793. // console.log(state)
  794. let TreeElement = $_(SyntaxTreeLeaf)
  795. let LeafElement = SyntaxTreeLeaf
  796. let add_to_output = (operand => append(state, operand))
  797. let put_operator = (operator => put(state, operator))
  798. let terminate = (t => BreakWith(put(state, sentinel)) )
  799. return transform(element, [
  800. { when_it_is: TreeElement, use: add_to_output },
  801. { when_it_is: LeafElement, use: l => transform(l.children, [
  802. { when_it_is: SimpleOperand, use: add_to_output },
  803. { when_it_is: SimpleOperator, use: put_operator },
  804. { when_it_is: Otherwise, use: terminate }
  805. ]) }
  806. ])
  807. })
  808. let EmptyState = Struct({
  809. output: $(x => x.length == 0),
  810. operators: $(x => x.length == 1)
  811. })
  812. return (is(final, EmptyState))? null: (function() {
  813. let result = get_result(final)
  814. return {
  815. amount: result.amount,
  816. name: 'Simple',
  817. children: [result]
  818. }
  819. })()
  820. }
  821. function parse (string) {
  822. console.log('parsing...')
  823. let tokens = get_tokens(string)
  824. let match = build_tree(Syntax, 'Module', tokens)
  825. let stuck_info = 'parser stuck: please check syntax'
  826. let stuck_err = parser_error(tokens[match.amount], stuck_info)
  827. stuck_err.if(match.amount < tokens.length)
  828. console.log('done')
  829. let tree = match
  830. return tree
  831. }