0

I have basic lisp interpreter that I'm working on https://codepen.io/jcubic/pen/gvvzdp?editors=1010

and I'm having problem with unquote-splicing and lisp code like this:

(print `(,@(list 1 2 3)))

the output list structure of this code, from parser, look like this:

(<#symbol 'print'> (<#symbol 'quasiquote'> (<#symbol 'unquote-splicing'> <#symbol 'list'> 1 2 3)))

I'm getting output as ((1 2 3)) and not (1 2 3), I've tested on biwascheme and the result should be (1 2 3).

console.log in print function indicate that it's list where car is (list 1 2 3) and not list itself.

my macro for quasiquote look like this:

  quasiquote: new Macro(function(arg) {
    var env = this;
    function recur(pair) {
      if (pair instanceof Pair) {
        if (Symbol.is(pair.car, 'unquote-splicing')) {
          // this if is first invoke of recur function for provided code
          var eval_pair = evaluate(pair.cdr, env);
          if (!eval_pair instanceof Pair) {
            throw new Error('Value of unquote-splicing need to be pair')
          }
          // here eval_pair.car is 1 (first item in list)
          return eval_pair;
        }
        if (Symbol.is(pair.car, 'unquote')) {
          return evaluate(pair.cdr, env);
        }
        var car = pair.car;
        if (car instanceof Pair) {
          car = recur(car);
        }
        var cdr = pair.cdr;
        if (cdr instanceof Pair) {
          cdr = recur(cdr);
        }
        return new Pair(car, cdr);
      }
      return pair;
    }
    return recur(arg);
})

Macro is just:

function Macro(fn) {
  this.fn = fn;
}
Macro.prototype.invoke = function(code, env) {
  return this.fn.call(env, code);
};

and my eval function look like this:

function evaluate(code, env) {
  env = env || global_env;
  var value;
  if (typeof code === 'undefined') {
    return;
  }
  var first = code.car;
  if (first instanceof Symbol) {
    var rest = code.cdr;
    // resolve return value from environment
    value = resolve(first, env);
    if (value instanceof Macro) {
      return value.invoke(rest, env);
    } else if (typeof value !== 'function') {
      throw new Error('Unknown function `' + first.name + '\'');
    } else {
      var args = [];
      var node = rest;
      while(true) {
        if (node !== nil) {
          args.push(evaluate(node.car, env));
        }
        if (node.cdr === nil) {
          break;
        }
        node = node.cdr;
      }
      return value.apply(env, args);
    }
  } else if (code instanceof Symbol) {
    value = resolve(code, env);
    if (value === 'undefined') {
      throw new Error('Unbound variable `' + code.name + '\'');
    }
    return value;
  } else {
    return code;
  }
}
Will Ness
  • 70,110
  • 9
  • 98
  • 181
jcubic
  • 61,973
  • 54
  • 229
  • 402
  • @WillNess thanks after some debugging I was able to fix my code. – jcubic Feb 21 '18 at 14:55
  • @WillNess I thought that quasiquote was working after that but then I found that "`(foo 1 2 3)" try to execute function foo event that it's in quote something is wrong with the parser I don't know if the quasiquote can be a macro, I've asked another very similar question https://stackoverflow.com/questions/48932481/lisp-macros-quotation-implementation-in-javascript – jcubic Feb 22 '18 at 19:14

0 Answers0