translator.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. 'use strict';
  2. const UsingExports = [
  3. 'G', 'K', 'Scope', 'HashObject', 'ListObject', 'Lookup', 'FormatString',
  4. 'Abstract', 'Structure', 'FiniteSet', 'Lambda', 'FunInst',
  5. 'define', 'apply', 'call', 'access', 'assign_outer', 'assert_bool',
  6. 'add_module', 'use_modules', 'import_modules', 'export_names'
  7. ]
  8. function normalize_operator_name (name) {
  9. check(normalize_operator_name, arguments, { name: Str })
  10. /**
  11. * if the operator is SimpleOperator, 'name' is name of token
  12. * if the operator is MapOperator, 'name' is matched string of token
  13. */
  14. let prefix = is(name[0], Char.Alphabet)? 'operator_': ''
  15. return (prefix + name.toLowerCase())
  16. }
  17. function escape_raw (string) {
  18. check(escape_raw, arguments, { string: Str })
  19. function f (char) {
  20. if (char == '\\') {
  21. return '\\\\'
  22. } else if (char == "'") {
  23. return "\\'"
  24. } else {
  25. return char
  26. }
  27. }
  28. return join(map_lazy(string, f), '')
  29. }
  30. function id_reference (string) {
  31. check(id_reference, arguments, { string: Str })
  32. let escaped = escape_raw(string)
  33. return `id('${escaped}')`
  34. }
  35. function string_of (leaf) {
  36. check(string_of, arguments, { leaf: SyntaxTreeLeaf })
  37. let token = leaf.children
  38. return token.matched.string
  39. }
  40. function use_string (leaf) {
  41. return string_of(leaf)
  42. }
  43. function use_first (tree) {
  44. assert(tree.children.length > 0)
  45. return translate(tree.children[0])
  46. }
  47. function children_hash (tree) {
  48. return fold(tree.children, {}, (child, h) => (h[child.name] = child, h))
  49. }
  50. function iterate_next (tree, next_part) {
  51. return iterate(tree, t => children_hash(t)[next_part], SyntaxTreeEmpty)
  52. }
  53. function translate_next(tree, current_part, next_part, separator, f) {
  54. check(translate_next, arguments, {
  55. current_part: Str, next_part: Str, separator: Str, f: Fun
  56. })
  57. let link = (x => join(x, separator))
  58. return link(map_lazy(
  59. iterate_next(tree, next_part),
  60. (t, i) => f(children_hash(t)[current_part], i)
  61. ))
  62. }
  63. function find_parameters (tree) {
  64. function crush (tree) {
  65. let Parameter = $(function (tree) {
  66. return (
  67. (tree.name == 'SimpleUnit')
  68. && assert(is(tree.children[0], SyntaxTreeLeaf))
  69. && is(tree.children[0].children, Token('Parameter'))
  70. ) || (tree.name == 'LambdaPara')
  71. })
  72. let FuncTree = $(tree => is(tree.name, one_of(
  73. 'FunDef', 'FunExpr', 'HashLambda', 'ListLambda', 'SimpleLambda'
  74. )))
  75. let Drop = $(function (x) { return x === this })
  76. let drop = (t => Drop)
  77. return apply_on(tree.children, chain(
  78. x => map_lazy(x, t => transform(t, [
  79. { when_it_is: SyntaxTreeEmpty, use: drop },
  80. { when_it_is: SyntaxTreeLeaf, use: drop },
  81. { when_it_is: FuncTree, use: drop },
  82. { when_it_is: Parameter, use: t => [t] },
  83. { when_it_is: Otherwise, use: t => crush(t) }
  84. ])),
  85. x => filter(x, (y => is_not(y, Drop))),
  86. x => concat(x),
  87. x => list(x)
  88. ))
  89. }
  90. let linear_list = map(crush(tree), function (para_unit) {
  91. let h = children_hash(para_unit)
  92. assert(has(h, 'Identifier'))
  93. let id_token = h.Identifier.children
  94. return {
  95. pos: id_token.position,
  96. name: id_token.matched.string
  97. }
  98. })
  99. let parameters = apply_on(linear_list, chain(
  100. x => fold(x, {}, function (item, hash) {
  101. let name = item.name
  102. if (hash[name]) {
  103. let r = Token.pos_compare(item.pos, hash[name].pos)
  104. if (r == -1) {
  105. hash[name] = item
  106. }
  107. } else {
  108. hash[name] = item
  109. }
  110. return hash
  111. }),
  112. x => map(x, (key, value) => value),
  113. x => x.sort((x,y) => Token.pos_compare(x.pos, y.pos)),
  114. x => map(x, item => item.name)
  115. ))
  116. return parameters
  117. }
  118. function function_string (body) {
  119. let head = `var id = Lookup(scope);`
  120. return `(function (scope) { ${head} ${body} })`
  121. }
  122. function translate_lambda (tree, type, get_val) {
  123. let parameters = apply_on(tree, chain(
  124. x => find_parameters(x),
  125. x => map_lazy(x, name => `'${escape_raw(name)}'`),
  126. x => join(x, ', ')
  127. ))
  128. let parameter_list = `[${parameters}]`
  129. let value = get_val(tree)
  130. let is_expr = (type == 'expr')
  131. let func = function_string(is_expr? `return ${value}`: value)
  132. return `Lambda(scope, ${parameter_list}, ${func})`
  133. }
  134. let Translate = {
  135. RawCode: function (leaf) {
  136. let string = string_of(leaf)
  137. let content = string.slice(2, string.length-2).trim()
  138. return `${content}`
  139. },
  140. /* ---------------------- */
  141. Constraint: use_first,
  142. Id: function (tree) {
  143. let id_id = $(tree => children_hash(tree).Identifier)
  144. let str_id = $(tree => children_hash(tree).RawString)
  145. let string = transform(tree, [
  146. { when_it_is: id_id, use: tree => string_of(tree.children[0]) },
  147. { when_it_is: str_id, use: function (tree) {
  148. let wrapped = string_of(tree.children[0])
  149. let content = wrapped.slice(1, wrapped.length-1)
  150. return content
  151. } }
  152. ])
  153. let escaped = escape_raw(string)
  154. return `'${escaped}'`
  155. },
  156. Module: function (tree) {
  157. let h = children_hash(tree)
  158. let prepare = join(map(
  159. UsingExports,
  160. name => `var ${name} = KumaExport.${name};`
  161. ), ' ')
  162. let scope = `var scope = Scope(G, 'local'); var id = Lookup(scope);`
  163. let module_name = translate(h.ModuleName)
  164. let content = translate(h.Program)
  165. let body = `${prepare} ${scope} ${module_name} ${content}`
  166. let exports = translate(h.ExportList)
  167. return `(function () { ${body}; ${exports} })()`
  168. },
  169. ModuleName: function (tree) {
  170. let h = children_hash(tree)
  171. let name = `var module_name = ${translate(h.Id)};`
  172. let add = `var export_object = add_module(module_name);`
  173. return `${name} ${add}`
  174. },
  175. AsList: function (tree) {
  176. let content = translate_next(
  177. tree, 'As', 'NextAs', ', ',
  178. function (item) {
  179. let name = translate(item.children[0])
  180. let alias = (
  181. (item.children.length > 1)?
  182. translate(item.children[2]): name
  183. )
  184. return `{ name: ${name}, alias: ${alias} }`
  185. }
  186. )
  187. return `[${content}]`
  188. },
  189. IdList: function (tree) {
  190. let content = translate_next(
  191. tree, 'Id', 'NextId', ', ', id => translate(id)
  192. )
  193. return `[${content}]`
  194. },
  195. Use: function (tree) {
  196. let h = children_hash(tree)
  197. let module_list = translate(h.AsList)
  198. return `use_modules(scope, ${module_list})`
  199. },
  200. Import: function (tree) {
  201. let h = children_hash(tree)
  202. let module_list = translate(h.IdList)
  203. return `import_modules(scope, ${module_list})`
  204. },
  205. Export: function (tree) {
  206. let h = children_hash(tree)
  207. let name_list = translate(h.AsList)
  208. return `export_names(export_object, scope, ${name_list})`
  209. },
  210. ExportList: function (tree) {
  211. let h = children_hash(tree)
  212. return (h.Export)? translate_next(
  213. tree, 'Export', 'NextExport', '; ',
  214. exp => translate(exp)
  215. ): ''
  216. },
  217. Program: function (tree) {
  218. return translate_next(
  219. tree, 'Command', 'NextCommand', '; ',
  220. cmd => translate(cmd)
  221. )
  222. },
  223. Command: use_first,
  224. Assign: function (tree) {
  225. let h = children_hash(tree)
  226. let LeftVal = children_hash(h.LeftVal)
  227. let head = translate(LeftVal.Id)
  228. let members = map_lazy(
  229. iterate_next(LeftVal.MemberNext, 'MemberNext'),
  230. t => translate(children_hash(t).Member)
  231. )
  232. let keys = map_lazy(
  233. iterate_next(LeftVal.KeyNext, 'KeyNext'),
  234. t => translate(children_hash(t).Key)
  235. )
  236. let total = list(cat(members, keys))
  237. let read = (total.length > 0)? total.slice(0, total.length-1): []
  238. let write = (total.length > 0)? total[total.length-1]: head
  239. let value = translate(h.Expr)
  240. return (total.length > 0)? (function() {
  241. let read_str = fold(read, `id(${head})`, function (key, reduced) {
  242. return `get(${reduced}, ${key})`
  243. })
  244. return `set(${read_str}, ${write}, ${value})`
  245. })(): `scope.replace(${write}, ${value})`
  246. },
  247. Let: function (tree) {
  248. let h = children_hash(tree)
  249. return `scope.emplace(${translate(h.Id)}, ${translate(h.Expr)})`
  250. },
  251. Outer: function (tree) {
  252. let h = children_hash(tree)
  253. return `assign_outer(scope, ${translate(h.Id)}, ${translate(h.Expr)})`
  254. },
  255. Return: function (tree) {
  256. let h = children_hash(tree)
  257. return `return ${translate(h.Expr)}`
  258. },
  259. Hash: function (tree) {
  260. let h = children_hash(tree)
  261. let content = (has(h, 'PairList'))? translate_next(
  262. h.PairList, 'Pair', 'NextPair', ', ', function (pair) {
  263. let h = children_hash(pair)
  264. return `${translate(h.Id)}: ${translate(h.Expr)}`
  265. }
  266. ): ''
  267. return `HashObject({${content}})`
  268. },
  269. List: function (tree) {
  270. let h = children_hash(tree)
  271. let content = (has(h, 'ItemList'))? translate_next(
  272. h.ItemList, 'Item', 'NextItem', ', ',
  273. (item) => `${use_first(item)}`
  274. ): ''
  275. return `ListObject([${content}])`
  276. },
  277. FiniteSet: function (tree) {
  278. let list = Translate.List(tree)
  279. return `FiniteSet(${list})`
  280. },
  281. Expr: use_first,
  282. MapOperand: use_first,
  283. MapOperator: function (tree) {
  284. let name = string_of(tree.children[0])
  285. let normalized = normalize_operator_name(name)
  286. let escaped = escape_raw(normalized)
  287. return `(apply(id('${escaped}')))`
  288. },
  289. MapExpr: function (tree) {
  290. let first_operand = use_first(tree)
  291. let h = children_hash(tree)
  292. let items = map(iterate_next(tree, 'MapNext'), children_hash)
  293. let shifted = items.slice(1, items.length)
  294. return fold(shifted, first_operand, function(h, reduced_string) {
  295. let operator_string = translate(h.MapOperator)
  296. let operand = h.FunExpr || h.BodyLambda || h.MapOperand
  297. let operand_string = translate(operand)
  298. return `${operator_string}(${reduced_string}, ${operand_string})`
  299. })
  300. },
  301. Filter: use_first,
  302. FilterList: function (tree) {
  303. let conditions = translate_next(
  304. tree, 'Filter', 'NextFilter', ' && ',
  305. f => `assert_bool(${translate(f)})`
  306. )
  307. return `${conditions}`
  308. },
  309. Concept: function (tree) {
  310. let h = children_hash(tree)
  311. let parameter = translate(h.Id)
  312. let filter_list = translate(h.FilterList)
  313. let f = function_string(`return ${filter_list}`)
  314. let checker = `Lambda(scope, [${parameter}], ${f})`
  315. return `Abstract(${checker})`
  316. },
  317. Struct: function (tree) {
  318. let h = children_hash(tree)
  319. let hash_object = translate(h.Hash)
  320. return `Structure(${hash_object})`
  321. },
  322. ListExprArgList: function (tree) {
  323. let table_content = translate_next(
  324. tree, 'ListExprArg', 'NextListExprArg', ', ',
  325. function (arg) {
  326. let h = children_hash(arg)
  327. return `${translate(h.Id)}: ${translate(h.Simple)}`
  328. }
  329. )
  330. let bind_code = translate_next(
  331. tree, 'ListExprArg', 'NextListExprArg', '; ',
  332. function (arg) {
  333. let h = children_hash(arg)
  334. let name = translate(h.Id)
  335. assert(name != `'__'`)
  336. return `scope.emplace(${name}, get(id('__'), ${name}))`
  337. }
  338. )
  339. return {
  340. bind_code: bind_code,
  341. iterables: `HashObject({${table_content}})`
  342. }
  343. },
  344. ListExprFilterList: function (tree) {
  345. let h = children_hash(tree)
  346. return (h.FilterList)? translate(h.FilterList): 'true'
  347. },
  348. IteratorExpr: function (tree) {
  349. let h = children_hash(tree)
  350. let expr = use_first(h.MapOperand)
  351. let arg_list = translate(h.ListExprArgList)
  352. let parameters = arg_list.parameters
  353. let bind_code = arg_list.bind_code
  354. let iterables = arg_list.iterables
  355. let filter_list = translate(h.ListExprFilterList)
  356. let f = function_string(`${bind_code}; return ${filter_list}`)
  357. let filter_lambda = `Lambda(scope, [], ${f})`
  358. let g = function_string(`${bind_code}; return ${expr}`)
  359. let mapper = `Lambda(scope, [], ${g})`
  360. let zipped = `K.zip.apply(${iterables})`
  361. let filtered = `K.filter.apply(${zipped}, ${filter_lambda})`
  362. return `K.map.apply(${filtered}, ${mapper})`
  363. },
  364. ListExpr: function (tree) {
  365. let iterator = Translate.IteratorExpr(tree)
  366. return `K.list.apply(${iterator})`
  367. },
  368. PairListExpr: function (tree) {
  369. let content = translate_next(
  370. tree, 'AdvPair', 'NextAdvPair', ', ',
  371. function (pair) {
  372. let h = children_hash(pair)
  373. let k = translate(h.MapOperand)
  374. let v = translate(h.Expr)
  375. return `HashObject({key: ${k}, value: ${v}})`
  376. }
  377. )
  378. return `ListObject([${content}])`
  379. },
  380. /* ---------------------- */
  381. SimpleLambda: function (tree) {
  382. return translate_lambda(tree, 'expr', function (tree) {
  383. let h = children_hash(tree)
  384. return translate(h.Simple || h.SimpleLambda)
  385. })
  386. },
  387. HashLambda: function (tree) {
  388. return translate_lambda(tree, 'expr', t => Translate.Hash(t))
  389. },
  390. ListLambda: function (tree) {
  391. return translate_lambda(tree, 'expr', t => Translate.List(t))
  392. },
  393. BodyLambda: function (tree) {
  394. return translate_lambda(tree, 'body', t => Translate.Body(t))
  395. },
  396. Body: function (tree) {
  397. let h = children_hash(tree)
  398. let program = translate(h.Program)
  399. return `${program}; return VoidObject`
  400. },
  401. ParaList: function (tree) {
  402. let h = children_hash(tree)
  403. let parameters = (has(h, 'Para'))? translate_next(
  404. tree, 'Para', 'NextPara', ', ', function (para) {
  405. let h = children_hash(para)
  406. let name = translate(h.Id)
  407. let constraint = translate(h.Constraint)
  408. let is_immutable = is(h.PassFlag, SyntaxTreeEmpty)
  409. let pass_policy = is_immutable? `'immutable'`: ({
  410. '&': `'dirty'`,
  411. '*': `'natural'`,
  412. })[string_of(h.PassFlag.children[0])]
  413. assert(is(pass_policy, Str))
  414. return `[${name},${constraint},${pass_policy}]`
  415. }
  416. ): ''
  417. return `[${parameters}]`
  418. },
  419. Target: function (tree) {
  420. let h = children_hash(tree)
  421. return (has(h, 'Constraint'))? translate(h.Constraint): 'K.Any'
  422. },
  423. FunExpr: function (tree) {
  424. let h = children_hash(tree)
  425. let Flag = h.FunFlag
  426. let effect = Flag? (function() {
  427. let h = children_hash(Flag)
  428. let flag = string_of(h.Keyword)
  429. return ({
  430. global: `'global'`,
  431. g: `'global'`,
  432. upper: `'upper'`,
  433. h: `'upper'`,
  434. local: `'local'`,
  435. f: `'local'`,
  436. })[flag]
  437. })(): `'local'`
  438. let paras = translate(h.ParaList)
  439. let target = translate(h.Target)
  440. let func = function_string(translate(h.Body))
  441. return `FunInst(scope, ${effect}, ${paras}, ${target}, ${func})`
  442. },
  443. FunDef: function (tree) {
  444. let h = children_hash(tree)
  445. let effect_raw = string_of(h.Effect.children[0])
  446. let effect = `'${effect_raw}'`
  447. let name = translate(h.Id)
  448. let paras = translate(h.ParaList)
  449. let target = translate(h.Target)
  450. let func = function_string(translate(h.Body))
  451. return `define(scope, ${name}, ${effect}, ${paras}, ${target}, ${func})`
  452. },
  453. /* ---------------------- */
  454. Wrapped: function (tree) {
  455. let h = children_hash(tree)
  456. return translate(h.Simple)
  457. },
  458. Simple: use_first,
  459. SimpleUnit: function (tree) {
  460. let args = tree.children.slice(1, tree.children.length)
  461. let operator = tree.children[0].children
  462. let op_name = operator.matched.name
  463. if (op_name == 'Parameter') { return translate(args[0]) }
  464. let normal = (name => escape_raw(normalize_operator_name(name)))
  465. let func_name = ({
  466. Call: 'call',
  467. Get: 'get',
  468. Access: 'access'
  469. })[op_name] || `(apply(id('${normal(op_name)}')))`
  470. let arg_str_list = map(args, a => translate(a))
  471. if (op_name == 'Access') { arg_str_list.push('scope') }
  472. let arg_list_str = join(arg_str_list, ', ')
  473. return `${func_name}(${arg_list_str})`
  474. },
  475. ArgList: function (tree) {
  476. let key_list = $(tree => has(children_hash(tree), 'KeyArg'))
  477. let index_list = $(tree => has(children_hash(tree), 'Arg'))
  478. let empty_list = Otherwise
  479. let list_str = transform(tree, [
  480. { when_it_is: key_list, use: tree => (translate_next(
  481. tree, 'KeyArg', 'NextKeyArg', ', ', function(key_arg) {
  482. let h = children_hash(key_arg)
  483. return `${translate(h.Id)}: ${translate(h.Simple)}`
  484. }
  485. ))},
  486. { when_it_is: index_list, use: tree => (translate_next(
  487. tree, 'Arg', 'NextArg', ', ', function(arg, i) {
  488. return `'${i}': ${use_first(arg)}`
  489. }
  490. ))},
  491. { when_it_is: empty_list, use: tree => '' }
  492. ])
  493. return `{${list_str}}`
  494. },
  495. Key: function (tree) {
  496. let h = children_hash(tree)
  497. return translate(h.Simple)
  498. },
  499. Identifier: function (leaf) {
  500. return id_reference(string_of(leaf))
  501. },
  502. Member: function (leaf) {
  503. let string = string_of(leaf)
  504. let escaped = escape_raw(string)
  505. return `'${escaped}'`
  506. },
  507. RawString: function (leaf) {
  508. let string = string_of(leaf)
  509. let content = string.slice(1, string.length-1)
  510. let escaped = escape_raw(content)
  511. return `'${escaped}'`
  512. },
  513. FormatString: function (leaf) {
  514. let string = string_of(leaf)
  515. let content = string.slice(1, string.length-1)
  516. let escaped = escape_raw(content)
  517. return `FormatString('${escaped}', id)`
  518. },
  519. Integer: use_string,
  520. Float: use_string,
  521. Exponent: use_string
  522. }
  523. function translate (tree) {
  524. assert(!has(tree, 'ok') || tree.ok == true)
  525. return Translate[tree.name](tree)
  526. }