This post is a continuation of LISPy-JSON Part 1, Part 2, Part-3 and Part-4 you should read these prior to reading the current post.
If-else is nothing but an extension of functions that implement binary operators. With a binary operator you evaluate the two expressions and operate on the result.
With the If-Else statement, you have three expressions:
- The Condition Expression
- Then Expression(s)
- Else Expression(s)
If the result of the condition expression is true, then you evaluate the Then Expression, else you evaluate the Else Expression,
result = if(condition){
/* result of then */
} else {
/* result of else */
}
To make this happen, we will also have to modify the original interpret function to return values
The complete diff can be seen here: https://github.com/avierr/LISPy-JSON-interpreter/commit/d285a22c729958aeaba3283746d519571b7567b9
Just to clean things up, we will refactor out the if-else implementation into it’s own function,
The diff for this can be here: https://github.com/avierr/LISPy-JSON-interpreter/commit/427ff1b9e276da2c69b1824c1e3de7e44006f07c
The entire code for the program is given below:
let program = [ { def: { 'a': 10 } }, { def: { 'b': 20 } }, { if: { '>': [{ val: 'a' }, { val: 'b' }] }, then: [{ print: 'a is greater than b' }], else: [{ print: 'b is greater than a' }] } ] let builtins = { print: (text) => { console.log(text) } } let binaryOperators = { '+': (a, b) => { return a + b }, '-': (a, b) => { return a - b }, '*': (a, b) => { return a * b }, '>': (a, b) => { return a > b }, '<': (a, b) => { return a < b }, '==': (a, b) => { return a == b }, '||': (a, b) => { return a || b }, '&&': (a, b) => { return a && b }, } interpret = (program, state) => { let returnValue; for (let stmt of program) { returnValue = exec(stmt, state) } return returnValue; }; varDefinition = (defObj, state) => { let variable = Object.keys(defObj)[0]; state[variable] = exec(defObj[variable], state) } varValue = (varKey, state) => { return state[varKey] } let ifStatement = (stmt, key, state) => { let condition = stmt[key] if (exec(condition, state)) { let thenStatements = stmt['then'] return interpret(thenStatements, state) } else { let elseStatements = stmt['else']; if (typeof elseStatements !== 'undefined') { return interpret(elseStatements, state) } } } exec = (stmt, state) => { if (typeof stmt === 'number' || typeof stmt === 'string') { return stmt; } let key = Object.keys(stmt)[0] if (typeof builtins[key] === 'function') { builtins[key](exec(stmt[key], state), state) } else if (typeof binaryOperators[key] === 'function') { let firstArgument = stmt[key][0]; let secondArgument = stmt[key][1]; return binaryOperators[key](exec(firstArgument, state), exec(secondArgument, state)) } else if (key === 'def') { let firstArgument = stmt[key] return varDefinition(firstArgument, state) } else if (key === 'val') { let firstArgument = stmt[key] return varValue(firstArgument, state) } else if (key === 'if') { return ifStatement(stmt, key, state) } else { console.error('unknown instruction: ' + key) } } interpret(program, {})
The program output is shown below:
$ node interpret.js
b is greater than a
The next post will focus on how to implement simple functions in our interpreter.
Tags: interpreter javascript