123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- const AST = require('./ast')
- const Env = require('./env')
- const OsloError = require('./osloError')
-
- module.exports = class Evaluator {
- eval(tree, env) {
- this.env = env
- this.error = false
-
- let evaluatedTree = []
-
- tree.forEach(node => {
- let evaluatedNode = this.evalNode(node, env)
-
- if (evaluatedNode) {
- if (evaluatedNode.constructor === OsloError) {
- this.error = evaluatedNode
- } else {
- evaluatedTree.push(evaluatedNode)
- }
- }
- })
-
- if (this.error) {
- return this.error
- }
-
- return evaluatedTree
- }
-
- evalNode(node, env) {
- if (!env) env = this.env
-
- switch (node.constructor) {
- case AST.Boolean:
- case AST.Number:
- case AST.String:
- return node
- case AST.Identifier:
- return env.get(node)
- case AST.Definition:
- this.env.set(node.symbol, node.value)
- return false
- case AST.LetBinding:
- let innerEnv = new Env(env)
-
- node.bindings.forEach(binding => {
- innerEnv.set(binding.key, binding.value)
- })
-
- return this.evalNode(node.body, innerEnv)
- case AST.Conditional:
- let result = this.evalNode(node.condition, env)
-
- if (result.constructor == AST.Boolean && result.value === true) {
- return this.evalNode(node.ifCase, env)
- }
-
- return this.evalNode(node.elseCase, env)
- case AST.Application:
- switch (node.function.constructor) {
- case AST.Identifier:
- return this.evalNode(
- new AST.Application({
- function: env.get(node.function),
- args: this.eval(node.args, env),
- }),
- env,
- )
- case AST.Lambda:
- let innerEnv = new Env(env)
-
- node.function.parameters.forEach((param, index) => {
- innerEnv.set(param, node.args[index])
- })
-
- return this.evalNode(node.function.body, innerEnv)
- case Function:
- let args = this.eval(node.args, env)
- args.unshift(this)
- return node.function.call(...args)
- }
- }
-
- return node
- }
- }
|