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 1.9KB

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