Как нарушить гигиену SweetJS для локальной переменной?

Я пытаюсь использовать SweetJS в моем проекте. Чтобы лучше понять и выучить SweetJS, я подумал, что начну с простого "классового" макроса (я знаю, что некоторые существуют, просто играя здесь...). Однако я не могу заставить SweetJS перестать связываться с моими локальными переменными "self" и "superCall". Есть идеи, что я делаю не так? мне бы хотелось var self=this оставаться var self=this вместо того, чтобы быть искалеченным.

macro class {
  case { _ $name extends $parent {
    constructor $cargs { $cbody ... }
    $($mname $margs { $mbody ... } ) ... 
  } } => {
    return #{
        function $name $cargs { var self=this,superCall=$parent.prototype; $cbody ... }
        $name.prototype = Object.create($parent.prototype);
        ($name.prototype.$mname = function $margs {var self=this,superCall=$parent.prototype; $mbody ... } ) ...;
    }
  }

  case { _ $name { $body ...} } => {
    return #{ class $name extends test2 { $body ... } };
  }
}

macro super {
    case { $macroName.$name( $($args (,) ...) ) } => {
       letstx $s = [makeIdent("self", #{ $macroName })];
       letstx $sC = [makeIdent("superCall", #{ $macroName })];
       return #{
          $sC.$name.call($s)
       };
    }

    case { $macroName( $args ... ) } => {
       letstx $s = [makeIdent("self", #{ $macroName })];
       letstx $sC = [makeIdent("superCall", #{ $macroName })];
       return #{
          superCall.constructor.call($s);
       };
    }
}

class test extends cow {
 constructor(arg1, arg2) {
     console.log('Hello world!');
 }
 method1(arg1, arg2) {
     super.method1();
 }
}

Это расширяется до:

function test(arg1, arg2) {
    var self$2 = this, superCall$2 = cow.prototype;
    console.log('Hello world!');
}
test.prototype = Object.create(cow.prototype);
test.prototype.method1 = function (arg1, arg2) {
    var self$2 = this, superCall$2 = cow.prototype;
    superCall.method1.call(self);
};

Как вы видете, var self=this был превращен в var self$2 = this, Как я могу предотвратить это? Я пытался использовать makeIdent, но я думаю, что делаю что-то не так. Есть идеи? Спасибо!

1 ответ

Решение

Чтобы нарушить гигиену, вы должны предоставить лексический контекст, выходящий за рамки макроса, в котором вы находитесь. В этом случае, используя $name связывая, вы на самом деле ссылаетесь на область видимости вне макроса, а не изнутри; это делает возможным нарушение гигиены в этом случае.

В результате, кажется, работает следующее:

macro class {
  case { _ $name extends $parent {
    constructor $cargs { $cbody ... }
    $($mname $margs { $mbody ... } ) ... 
  } } => {
    letstx $self = [makeIdent("self", #{ $name })];
    return #{
        function $name $cargs { var $self=this,superCall=$parent.prototype; $cbody ... }
        $name.prototype = Object.create($parent.prototype);
        ($name.prototype.$mname = function $margs {var $self=this,superCall=$parent.prototype; $mbody ... } ) ...;
    }
  }

  case { _ $name { $body ...} } => {
    return #{ class $name extends test2 { $body ... } };
  }
}

Обратите внимание, что я создал идентификатор с именем $self и использовал имя класса в качестве моего объекта синтаксиса.

Узнайте больше о нарушении гигиены здесь.

Другие вопросы по тегам