A templating language that looks like Lisp and compiles to HTML
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

evaluator.js 2.2KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. const AST = require('./ast')
  2. const Env = require('./env')
  3. const OsloError = require('./osloError')
  4. module.exports = class Evaluator {
  5. eval(tree, env) {
  6. this.env = env
  7. this.error = false
  8. let evaluatedTree = []
  9. tree.forEach(node => {
  10. let evaluatedNode = this.evalNode(node)
  11. if (evaluatedNode) {
  12. if (evaluatedNode.constructor === OsloError) {
  13. this.error = evaluatedNode
  14. } else {
  15. evaluatedTree.push(evaluatedNode)
  16. }
  17. }
  18. })
  19. if (this.error) {
  20. return this.error
  21. }
  22. return evaluatedTree
  23. }
  24. evalNode(node, env) {
  25. if (!env) env = this.env
  26. switch (node.constructor) {
  27. case AST.Boolean:
  28. case AST.Number:
  29. case AST.String:
  30. return node
  31. case AST.Identifier:
  32. return env.get(node)
  33. case AST.Definition:
  34. this.env.set(node.symbol, node.value)
  35. return false
  36. case AST.LetBinding:
  37. let innerEnv = new Env(env)
  38. node.bindings.forEach(binding => {
  39. innerEnv.set(binding.key, binding.value)
  40. })
  41. return this.evalNode(node.body, innerEnv)
  42. case AST.Conditional:
  43. let result = this.evalNode(node.condition, env)
  44. if (result.constructor == AST.Boolean && result.value === true) {
  45. return this.evalNode(node.ifCase, env)
  46. }
  47. return this.evalNode(node.elseCase, env)
  48. case AST.Application:
  49. switch (node.function.constructor) {
  50. case AST.Identifier:
  51. return this.evalNode(
  52. new AST.Application({
  53. function: env.get(node.function),
  54. args: node.args,
  55. }),
  56. env,
  57. )
  58. case AST.Lambda:
  59. let innerEnv = new Env(env)
  60. node.function.parameters.forEach((param, index) => {
  61. innerEnv.set(param, node.args[index])
  62. })
  63. return this.evalNode(node.function.body, innerEnv)
  64. case Function:
  65. let args = node.args.map(arg => {
  66. return this.evalNode(arg, env)
  67. })
  68. args.unshift(this)
  69. return node.function.call(...args)
  70. }
  71. }
  72. return node
  73. }
  74. }