function.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /**
  2. * Function & Scope
  3. *
  4. * In order to provide runtime type check for functions
  5. * and change the behaviour of variable declaration,
  6. * it is necessary to wrap ordinary JavaScript functions
  7. * into Wrapped Functions and define our own scope objects.
  8. * A Wrapped Function is also a valid JavaScript function,
  9. * but a [WrapperInfo] object is added to it.
  10. */
  11. const WrapperInfo = Symbol('WrapperInfo')
  12. const BareFuncDesc = Symbol('BareFuncDesc')
  13. let Wrapped = Ins(ES.Function, $(x => typeof x[WrapperInfo] == 'object'))
  14. let Bare = Ins(ES.Function, $(x => typeof x[WrapperInfo] != 'object'))
  15. let ArgError = new Map([
  16. [1, 'arg_wrong_quantity'],
  17. [2, 'arg_invalid']
  18. ])
  19. pour(Types, {
  20. ES_Function: Bare,
  21. Wrapped: Wrapped,
  22. Function: Ins(Wrapped, $(f => has('context', f[WrapperInfo]))),
  23. Overload: Ins(Wrapped, $(f => has('functions', f[WrapperInfo]))),
  24. Binding: Ins(Wrapped, $(f => has('pointer', f[WrapperInfo])))
  25. })
  26. function call_by_js (f, args) {
  27. assert(is(f, Types.Wrapped))
  28. assert(is(args, Types.List))
  29. return f.apply(null, args)
  30. }
  31. function inject_desc (f, desc) {
  32. assert(is(f, Bare))
  33. // inject description for bare JavaScript functions
  34. f[BareFuncDesc] = `Runtime.${desc}`
  35. // the injected description text will be shown in call stack backtrace
  36. return f
  37. }
  38. inject_desc(call_by_js, 'call_by_js')
  39. /**
  40. * Definition of Parameter & Function Prototype
  41. */
  42. let Parameter = format({
  43. name: Types.String,
  44. type: Type
  45. })
  46. let Prototype = format({
  47. value_type: Type,
  48. parameters: TypedList.of(Parameter)
  49. }, proto => no_repeat(map(proto.parameters, p => p.name)) )
  50. /**
  51. * Scope Object
  52. *
  53. * There are two kinds of variables can be declared in a scope,
  54. * 1. fixed variable: defined by `let NAME [:TYPE] = VALUE`
  55. * 2. non-fixed variable: defined by `var NAME [:TYPE] = VALUE`
  56. * The value of fixed variable cannot be changed to another value,
  57. * but it does NOT mean it's a constant, because the inner structure of
  58. * the value actually can be changed, for example, the command
  59. * `let hash = { 'a': 0 }; set hash['a'] = 1` is legal, but the command
  60. * `let num = 0; reset num = 1` is illegal.
  61. */
  62. class Scope {
  63. constructor (context, data = {}, read_only = false) {
  64. assert(context === null || context instanceof Scope)
  65. assert(is(data, Types.Hash))
  66. // upper scope
  67. this.context = context
  68. // variables in this scope
  69. this.data = copy(data)
  70. // types of non-fixed variables
  71. this.types_of_non_fixed = {}
  72. // is it read-only? (e.g. the global scope is read-only)
  73. this.read_only = read_only
  74. // context-depended operators
  75. this.operators = {}
  76. if (read_only) {
  77. Object.freeze(this.data)
  78. }
  79. Object.freeze(this)
  80. }
  81. is_fixed (variable) {
  82. assert(is(variable, Types.String))
  83. return !has(variable, this.types_of_non_fixed)
  84. }
  85. has (variable) {
  86. assert(is(variable, Types.String))
  87. return has(variable, this.data)
  88. }
  89. declare (variable, initial_value, is_fixed = true, type = Any) {
  90. assert(!this.read_only)
  91. assert(is(variable, Types.String))
  92. assert(is(is_fixed, Types.Bool))
  93. assert(is(type, Type))
  94. ensure(!this.has(variable), 'variable_declared', variable)
  95. ensure(is(initial_value, type), 'variable_invalid', variable)
  96. this.data[variable] = initial_value
  97. if (!is_fixed) {
  98. this.types_of_non_fixed[variable] = type
  99. }
  100. return Void
  101. }
  102. add_function (name, f) {
  103. // overload functions with a common name
  104. assert(is(name, Types.String))
  105. assert(is(f, Types.Function))
  106. let existing = this.find(name)
  107. if (existing !== NotFound) {
  108. if (is(existing, Types.Function)) {
  109. let g = overload([existing, f], name)
  110. if (this.has(name)) {
  111. this.reset(name, g)
  112. } else {
  113. this.declare(name, g, false)
  114. }
  115. } else if (is(existing, Types.Overload)) {
  116. let g = overload_added(f, existing, name)
  117. if (this.has(name)) {
  118. this.reset(name, g)
  119. } else {
  120. this.declare(name, g, false)
  121. }
  122. } else {
  123. this.declare(name, f, false)
  124. }
  125. } else {
  126. this.declare(name, f, false)
  127. }
  128. return Void
  129. }
  130. define_mount (f) {
  131. assert(is(f, ES.Function))
  132. this.operators.mount = f
  133. }
  134. define_push (f) {
  135. assert(is(f, ES.Function))
  136. this.operators.push = f
  137. }
  138. mount (i) {
  139. let s = find(this.iter_scope_chain(), s => s.operators.mount != null)
  140. ensure(s !== NotFound, 'invalid_mount')
  141. assert(is(s.operators.mount, ES.Function))
  142. return s.operators.mount
  143. }
  144. push (object) {
  145. let s = find(this.iter_scope_chain(), s => s.operators.push != null)
  146. ensure(s !== NotFound, 'invalid_push')
  147. assert(is(s.operators.push, ES.Function))
  148. return s.operators.push
  149. }
  150. reset (variable, new_value) {
  151. assert(is(variable, Types.String))
  152. let scope = this
  153. while (scope !== null) {
  154. if (scope.has(variable)) {
  155. break
  156. }
  157. scope = scope.context
  158. }
  159. ensure(scope !== null, 'variable_not_declared', variable)
  160. ensure(!scope.is_fixed(variable), 'variable_fixed', variable)
  161. let type_ok = is(new_value, scope.types_of_non_fixed[variable])
  162. ensure(type_ok, 'variable_invalid', variable)
  163. scope.data[variable] = new_value
  164. return Void
  165. }
  166. lookup (variable) {
  167. assert(is(variable, Types.String))
  168. let value = this.find(variable)
  169. ensure(value !== NotFound, 'variable_not_found', variable)
  170. return value
  171. }
  172. try_to_declare (variable, initial_value, is_fixed, type) {
  173. assert(!this.read_only)
  174. assert(is(variable, Types.String))
  175. if (!this.has(variable)) {
  176. this.declare(variable, initial_value, is_fixed, type)
  177. }
  178. }
  179. iter_scope_chain () {
  180. return iterate (
  181. this,
  182. scope => scope.context,
  183. scope => scope === null
  184. )
  185. }
  186. find (variable) {
  187. assert(is(variable, Types.String))
  188. return find(map(this.iter_scope_chain(), (scope, depth) => {
  189. if (scope.has(variable)) {
  190. let value = scope.data[variable]
  191. // got a fixed variable
  192. if (scope.is_fixed(variable)) {
  193. return value
  194. }
  195. // got a non-fixed variable, check consistency
  196. let ok = is(value, scope.types_of_non_fixed[variable])
  197. ensure(ok, 'variable_inconsistent', variable)
  198. return value
  199. } else {
  200. return NotFound
  201. }
  202. }), object => object !== NotFound)
  203. }
  204. find_function (variable) {
  205. // used by `call_method()` in `oo.js`
  206. assert(is(variable, Types.String))
  207. let result = find(map(this.iter_scope_chain(), (scope, depth) => {
  208. if (scope.has(variable)) {
  209. let value = scope.data[variable]
  210. // not function, lookup upper scope
  211. if (!is(value, ES.Function)) {
  212. return { value: NotFound }
  213. }
  214. // got a fixed variable
  215. if (scope.is_fixed(variable)) {
  216. return { value, ok: true }
  217. }
  218. // got a non-fixed variable, check consistency
  219. let ok = is(value, scope.types_of_non_fixed[variable])
  220. return { value, ok }
  221. } else {
  222. return { value: NotFound }
  223. }
  224. }), result => result.value !== NotFound)
  225. return (result !== NotFound)? result: { value: NotFound }
  226. }
  227. }
  228. /* shorthand */
  229. let new_scope = context => new Scope(context)
  230. /**
  231. * Wraps a bare function
  232. *
  233. * @param context Scope
  234. * @param proto Prototype
  235. * @param desc string
  236. * @param raw Bare
  237. * @return Function
  238. */
  239. function wrap (context, proto, desc, raw) {
  240. assert(context === null || context instanceof Scope)
  241. assert(is(proto, Prototype))
  242. assert(is(raw, Bare))
  243. assert(is(desc, Types.String))
  244. let invoke = (args, use_ctx = null, check = true) => {
  245. // arguments may have been checked by overload
  246. if (check) {
  247. let result = check_args(args, proto)
  248. ensure (
  249. result.ok, ArgError.get(result.err),
  250. result.info, args.length
  251. )
  252. }
  253. // generate scope
  254. let scope = new Scope(use_ctx || context)
  255. inject_args(args, proto, scope)
  256. let value = raw(scope)
  257. ensure(is(value, proto.value_type), 'retval_invalid')
  258. // return the value after type check
  259. return value
  260. }
  261. let wrapped = give_arity (
  262. (...args) => call(wrapped, args, '<JS>'),
  263. proto.parameters.length
  264. )
  265. foreach(proto.parameters, p => Object.freeze(p))
  266. Object.freeze(proto.parameters)
  267. Object.freeze(proto)
  268. let info = { context, invoke, proto, desc, raw }
  269. Object.freeze(info)
  270. wrapped[WrapperInfo] = info
  271. Object.freeze(wrapped)
  272. return wrapped
  273. }
  274. /**
  275. * Creates a scope for static variables
  276. *
  277. * @param f function
  278. * @param context Scope
  279. * @return Scope
  280. */
  281. function get_static (f, context) {
  282. assert(is(f, Bare))
  283. let scope = new Scope(context)
  284. f(scope) // execute the static block
  285. return scope
  286. }
  287. /**
  288. * Checks if arguments are valid according to a function prototype
  289. *
  290. * @param args array
  291. * @param proto Prototype
  292. * @return { ok: boolean, err: key of `ArgError`, info: any }
  293. */
  294. function check_args (args, proto) {
  295. // no type assertion here, because only called by `wrap()` and `overload()`
  296. let arity = proto.parameters.length
  297. // check if argument quantity correct
  298. if (arity != args.length) {
  299. return { ok: false, err: 1, info: arity }
  300. }
  301. // check types
  302. for (let i=0; i<arity; i++) {
  303. let parameter = proto.parameters[i]
  304. let arg = args[i]
  305. let name = parameter.name
  306. // check if the argument is of required type
  307. if( !is(arg, parameter.type) ) {
  308. return { ok: false, err: 2, info: name }
  309. }
  310. }
  311. return { ok: true }
  312. }
  313. /**
  314. * Injects arguments to specified scope
  315. *
  316. * @param args array
  317. * @param proto Prototype
  318. * @param scope Scope
  319. */
  320. function inject_args (args, proto, scope) {
  321. // no type assertion here, because only called by `wrap()`
  322. let arity = proto.parameters.length
  323. for (let i=0; i<arity; i++) {
  324. let parameter = proto.parameters[i]
  325. scope.declare(parameter.name, args[i], false, parameter.type)
  326. }
  327. }
  328. /**
  329. * Overloads some wrapped functions into a single wrapped function
  330. *
  331. * @param functions Function[]
  332. * @param name string
  333. * @return Overload
  334. */
  335. function overload (functions, name) {
  336. assert(is(functions, TypedList.of(Types.Function)))
  337. assert(is(name, Types.String))
  338. functions = copy(functions)
  339. Object.freeze(functions)
  340. let desc = `${name}[${functions.length}]`
  341. let only1 = (functions.length == 1)
  342. let invoke = null
  343. if (only1) {
  344. // this special handling makes error message more clear
  345. invoke = (args, use_ctx = null) => {
  346. let info = functions[0][WrapperInfo]
  347. push_call(2, info.desc)
  348. try {
  349. return info.invoke(args, use_ctx)
  350. } catch (e) {
  351. throw e
  352. } finally {
  353. pop_call()
  354. }
  355. }
  356. } else {
  357. invoke = (args, use_ctx = null) => {
  358. let info_list = []
  359. let result_list = []
  360. let ok = false
  361. let info = null
  362. let i = 0
  363. for (let f of rev(functions)) {
  364. info_list.push(f[WrapperInfo])
  365. result_list.push(check_args(args, info_list[i].proto))
  366. if (result_list[i].ok) {
  367. info = info_list[i]
  368. ok = true
  369. break
  370. }
  371. i += 1
  372. }
  373. if (ok) {
  374. push_call(2, info.desc)
  375. try {
  376. return info.invoke(args, use_ctx)
  377. } catch (e) {
  378. throw e
  379. } finally {
  380. pop_call()
  381. }
  382. } else {
  383. let n = i
  384. let available = join(map(count(n), i => {
  385. let r = result_list[i]
  386. return (
  387. info_list[i].desc
  388. + ' (' + get_msg (
  389. ArgError.get(r.err),
  390. [r.info, args.length]
  391. ) + ')'
  392. )
  393. }), LF)
  394. ensure(false, 'no_matching_function', available)
  395. }
  396. }
  397. }
  398. let o = (...args) => call(o, args, '<JS>')
  399. let info = Object.freeze({ functions, invoke, name, desc })
  400. Object.freeze(info)
  401. o[WrapperInfo] = info
  402. Object.freeze(o)
  403. return o
  404. }
  405. /**
  406. * Creates a new overload with a new function added to the old one
  407. *
  408. * @param f Function
  409. * @param o Overload
  410. * @param name string
  411. * @return Overload
  412. */
  413. function overload_added (f, o, name) {
  414. assert(is(o, Types.Overload))
  415. return overload([...o[WrapperInfo].functions, f], name)
  416. }
  417. /**
  418. * Creates a new overload from `o1` concatenated with `o2`
  419. *
  420. * @param o2 Overload
  421. * @param o1 Overload
  422. * @param name string
  423. * @return Overload
  424. */
  425. function overload_concated (o2, o1, name) {
  426. assert(is(o2, Types.Overload))
  427. assert(is(o1, Types.Overload))
  428. return overload(list(
  429. cat(o1[WrapperInfo].functions, o2[WrapperInfo].functions)
  430. ), name)
  431. }
  432. /**
  433. * Creates a function binding pointing to `f` with replaced context
  434. *
  435. * @param f Wrapped
  436. * @param context Scope
  437. * @return Binding
  438. */
  439. function bind_context (f, context) {
  440. assert(is(f, Types.Wrapped))
  441. assert(context instanceof Scope)
  442. f = cancel_binding(f)
  443. let f_invoke = f[WrapperInfo].invoke
  444. let desc = f[WrapperInfo].desc
  445. let invoke = function (args, use_ctx = null) {
  446. assert(use_ctx === null)
  447. return f_invoke(args, context)
  448. }
  449. let binding = (...args) => call(binding, args, '<JS>')
  450. let info = { invoke, desc, pointer: f, bound: context }
  451. Object.freeze(info)
  452. binding[WrapperInfo] = info
  453. Object.freeze(binding)
  454. return binding
  455. }
  456. /**
  457. * Creates a new function as `f` embraced into another context
  458. *
  459. * @param f Wrapped
  460. * @param context Scope
  461. * @return Wrapped
  462. */
  463. function embrace_in_context (f, context) {
  464. assert(is(f, Types.Wrapped))
  465. assert(context instanceof Scope)
  466. f = cancel_binding(f)
  467. if (is(f, Types.Overload)) {
  468. return overload(f[WrapperInfo].functions.map(F => {
  469. F = F[WrapperInfo]
  470. return wrap(context, F.proto, F.desc, F.raw)
  471. }), f[WrapperInfo].name)
  472. } else if(is(f, Types.Function)) {
  473. let F = f[WrapperInfo]
  474. return wrap(context, F.proto, F.desc, F.raw)
  475. } else {
  476. assert(false)
  477. }
  478. }
  479. /**
  480. * Deref `f` if it is a binding
  481. *
  482. * @param f Wrapped
  483. * @return Wrapped
  484. */
  485. function cancel_binding (f) {
  486. assert(is(f, Types.Wrapped))
  487. return f[WrapperInfo].pointer || f
  488. }
  489. /**
  490. * Calls a callable object, put debug info onto the call stack
  491. *
  492. * @param f Callable
  493. * @param args array
  494. * @param file string
  495. * @param row integer
  496. * @param col integer
  497. */
  498. function call (f, args, file = null, row = -1, col = -1) {
  499. assert(is(args, Types.List))
  500. if (is(f, Types.TypeTemplate)) {
  501. f = f.inflate
  502. } else if (is(f, Types.Class)) {
  503. f = f.create
  504. } else if (is(f, Types.Schema)) {
  505. f = f.create_struct_from_another
  506. }
  507. let call_type = file? CALL_FROM_SCRIPT: CALL_FROM_BUILT_IN
  508. if (is(f, Types.Wrapped)) {
  509. let info = f[WrapperInfo]
  510. push_call(call_type, info.desc, file, row, col)
  511. try {
  512. return info.invoke(args)
  513. } catch (e) {
  514. throw e
  515. } finally {
  516. pop_call()
  517. }
  518. } else if (is(f, ES.Function)) {
  519. let desc = f[BareFuncDesc] || get_summary(f.toString())
  520. push_call(call_type, desc, file, row, col)
  521. try {
  522. return f.apply(null, args)
  523. } catch (e) {
  524. throw e
  525. } finally {
  526. pop_call()
  527. }
  528. } else {
  529. ensure(false, 'non_callable', `${file} (row ${row}, column ${col})`)
  530. }
  531. }
  532. /**
  533. * Function Declaration Parser for Built-in Functions
  534. *
  535. * @param string function FUNC_NAME (NAME1: TYPE1, NAME2: TYPE2, ...) -> TYPE
  536. * @return { name: String, proto: Prototype }
  537. */
  538. function parse_decl (string) {
  539. function parse_template_arg (arg_str) {
  540. if (arg_str == 'true') { return true }
  541. if (arg_str == 'false') { return false }
  542. if (!Number.isNaN(Number(arg_str))) { return Number(arg_str) }
  543. if (arg_str.match(/^'[^']*'$/) != null) { return arg_str.slice(1, -1) }
  544. assert(has(arg_str, Types))
  545. return Types[arg_str]
  546. }
  547. function parse_type (type_str) {
  548. // Note: Type names are resolved by `Types[TYPE_NAME]`
  549. match = type_str.match(/([^<]+)<(.+)>/)
  550. if (match != null) {
  551. let template_str = match[1]
  552. let args_str = match[2]
  553. let arg_strs = args_str.split(',').map(a => a.trim())
  554. let args = arg_strs.map(parse_template_arg)
  555. assert(has(template_str, Types))
  556. // note: template.inflate() already bound, apply(null, ...) is OK
  557. return Types[template_str].inflate.apply(null, args)
  558. } else {
  559. assert(has(type_str, Types))
  560. return Types[type_str]
  561. }
  562. }
  563. let match = string.match(/function +([^( ]+) +\(([^)]*)\) *-> *(.+)/)
  564. let [_, name, params_str, value_str] = match
  565. let has_p = params_str.trim().length > 0
  566. let parameters = has_p? (list(map(params_str.split(','), para_str => {
  567. para_str = para_str.trim()
  568. let match = para_str.match(/([^ :]+) *: *(.+)/)
  569. let [_, name, type_str] = match
  570. let type = parse_type(type_str)
  571. let parameter = { name, type }
  572. Object.freeze(parameter)
  573. return parameter
  574. }))): []
  575. Object.freeze(parameters)
  576. let value_type = parse_type(value_str)
  577. let proto = { parameters, value_type }
  578. Object.freeze(proto)
  579. assert(is(proto, Prototype))
  580. return { name, proto }
  581. }
  582. /**
  583. * Built-in Function Creator
  584. *
  585. * @param decl_string string
  586. * @param body function (ARG1, ARG, ...) => RETURN_VALUE
  587. * @return Function
  588. */
  589. function fun (decl_string, body) {
  590. let parsed = parse_decl(decl_string)
  591. assert(is(body, ES.Function))
  592. assert(!is(body, Types.Wrapped))
  593. let desc = decl_string.replace(/^function */, '')
  594. return wrap(null, parsed.proto, desc, scope => {
  595. return body.apply(
  596. null,
  597. list(cat(
  598. map(parsed.proto.parameters, p => scope.lookup(p.name)),
  599. [scope]
  600. ))
  601. )
  602. })
  603. }
  604. /**
  605. * Built-in Overload Creator
  606. *
  607. * @param name string
  608. * @param args array of (string | function)
  609. * @return Overload
  610. */
  611. function f (name, ...args) {
  612. // see usage at `built-in/functions.js`
  613. assert(args.length % 2 == 0)
  614. let functions = list(map(
  615. count(args.length/2),
  616. i => fun(args[i*2], args[i*2+1])
  617. ))
  618. return overload(functions, name)
  619. }