Advertisement
Guest User

Untitled

a guest
Aug 23rd, 2019
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.27 KB | None | 0 0
  1. const tokeniseInput = function(inputString) {
  2. const tokenise = function(tokens, currentToken, remaining) {
  3. if (remaining.length === 0) {
  4. return tokens;
  5. }
  6.  
  7. const [currentChar, ...newRemaining] = remaining;
  8.  
  9. // Only include the current token if it is not empty
  10. const tokensMaybeWithCurrent = function() {
  11. if (currentToken === '') {
  12. return tokens;
  13. } else {
  14. return [...tokens, currentToken];
  15. }
  16. }
  17.  
  18. if (currentChar === ' ') {
  19. return tokenise(tokensMaybeWithCurrent(), '', newRemaining);
  20. } else if (currentChar === '(' || currentChar === ')') {
  21. return tokenise([...tokensMaybeWithCurrent(), currentChar], '', newRemaining);
  22. } else {
  23. return tokenise(tokens, currentToken + currentChar, newRemaining)
  24. }
  25. }
  26. return tokenise([], '', inputString);
  27. }
  28.  
  29. const buildAST = function(tokens) {
  30. const parseToken = function(token) {
  31. const intVal = parseInt(token);
  32. if (!isNaN(intVal)) {
  33. return {type: 'literal', value: intVal};
  34. }
  35. const floatVal = parseFloat(token);
  36. if (!isNaN(floatVal)) {
  37. return {type: 'literal', value: intVal};
  38. }
  39. return {type: 'symbol', token};
  40. };
  41.  
  42. const getOp = function(opToken) {
  43. if (opToken === 'begin') {
  44. return {type: 'begin'};
  45. } else if (opToken === 'if') {
  46. return {type: 'conditional'};
  47. } else if (opToken === 'define') {
  48. return {type: 'definition'};
  49. } else {
  50. return {type: 'call', value: parseToken(opToken)};
  51. }
  52. }
  53.  
  54. const processUntilEndOfExpression = function(processed, inputTokens) {
  55. if (inputTokens.length === 0) {
  56. return processed;
  57. }
  58.  
  59. const [token, ...remainingTokens] = inputTokens;
  60.  
  61. if (token === '(') {
  62. const [newNode, newRemaining] = buildNode(remainingTokens);
  63. return processUntilEndOfExpression([...processed, newNode], newRemaining);
  64. } if (token === ')') {
  65. return [processed, remainingTokens];
  66. } else {
  67. return processUntilEndOfExpression([...processed, parseToken(token)], remainingTokens);
  68. }
  69. };
  70.  
  71. const buildNode = function(tokens) {
  72. const [opToken, ...remainingTokens] = tokens;
  73.  
  74. const [args, newRemaining] = processUntilEndOfExpression([], remainingTokens);
  75. return [{...getOp(opToken), args}, newRemaining];
  76. };
  77.  
  78. return processUntilEndOfExpression([], tokens)[0];
  79. }
  80.  
  81. const parse = function(inputString) {
  82. return buildAST(tokeniseInput(inputString));
  83. }
  84.  
  85. const eval = function(expression) {
  86. const baseEnv = Object.freeze({
  87. '+': (x, y) => x + y,
  88. '-': (x, y) => x - y,
  89. '*': (x, y) => x * y,
  90. '/': (x, y) => x / y,
  91. '<': (x, y) => x < y,
  92. '>': (x, y) => x > y,
  93. 'sqrt': Math.sqrt,
  94. '^': Math.pow,
  95. 'pi': Math.PI,
  96. });
  97.  
  98. const doEval = function(exp, env) {
  99. if (exp.type === 'symbol') {
  100. return {result: env[exp.token], env};
  101. } else if (exp.type === 'literal') {
  102. return {result: exp.value, env};
  103. } else if (exp.type === 'begin') {
  104. return exp.args.reduce(({env}, exp) => {
  105. return doEval(exp, env);
  106. }, {result: null, env});
  107. } else if (exp.type === 'definition') {
  108. const [symbol, valueExp] = exp.args;
  109.  
  110. const newEnv = {
  111. ...env,
  112. [symbol.token]: doEval(valueExp, env).result
  113. };
  114.  
  115. return {result: null, env: newEnv};
  116. } else if (exp.type === 'call') {
  117. const proc = doEval(exp.value, env).result;
  118.  
  119. return {
  120. result: proc(...exp.args.map(exp => doEval(exp, env).result)),
  121. env
  122. };
  123. } else if (exp.type === 'conditional') {
  124. const [conditionExp, ifTrue, ifFalse] = exp.args;
  125. return doEval(conditionExp).result ? doEval(ifTrue).result : doEval(ifFalse).result;
  126. }
  127. }
  128.  
  129. return doEval(expression, baseEnv).result;
  130. }
  131.  
  132. const program = '(begin (define a 3) (define b 6) (sqrt (+ (^ a 2) (^ b 2))))';
  133. const ast = parse(program);
  134. console.log(eval(ast));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement