2008-10-11 13 views
16

Wiem, że JavaScript nie obsługuje makr (w stylu Lisp), ale zastanawiałem się, czy ktoś ma rozwiązanie, które może symulować makra? Przeszukałem go i jedno z rozwiązań sugerowało użycie eval(), ale jak powiedział, byłoby dość kosztowne.Jak mogę symulować makra w JavaScript?

Nie muszą być bardzo wymyślne. Po prostu chcę z nimi robić proste rzeczy. I nie powinno to znacznie utrudniać debugowania :)

Odpowiedz

-2

Javascript jest interpretowany. Eval nie jest bardziej kosztowny niż cokolwiek innego w JavaScript.

+0

Wrong! James, przeczytaj na ten temat: http: //stackoverflow.com/questions/86513/why-is-using-javascript-eval-function-a-bad-idea#87260 i zatwierdź swoje opinie, zanim zaczniesz wprowadzać w błąd. Ciąg przekazywany do eval musi być analizowany/interpretowany za każdym razem, gdy wywoływany jest eval! – Ash

+0

Tak, ciąg przekazywany do eval musi być analizowany za każdym razem, gdy wywoływana jest funkcja eval - ale tak samo musi być każda inna linia javascript. tak działają tłumacze. Jeśli chodzi o odpowiedź, z którą się łączysz, nigdy nie wspomina o szybkości, po prostu "dużo łatwiejsza do odczytania, a także mniej potencjalnie błędna" –

+2

Zapewniam, że prawdopodobnie tak było w przypadku JavaScript w przeglądarkach powiedzmy około 2000, ale dzisiaj tam są poważne optymalizacje stosowane do zwykłego kodu Javascript (tj. nie-eval'd), a to będzie kontynuowane. Kod w ciągu znaków w dowolnym języku nie może być zoptymalizowany również w pobliżu. – Ash

22

Można użyć parenscript. Da ci to makra dla Javascript.

+0

-1 Podczas gdy parenscript był w porządku w 2008 roku, powinieneś naprawdę używać ClojureScript teraz. –

+0

Różne rozwiązania ... Parenscript to raczej cienka warstwa, w przeciwieństwie do ClojureScript. –

+2

Nie tylko różne rozwiązania, różne języki też. –

5

Pisałem emulator gameboy w javascript i symulować makr dla emulacji procesora w ten sposób:

makro kodu (funkcja zwraca ciąg znaków z kodu makra):

function CPU_CP_A(R,C) { // this function simulates the CP instruction, 
    return ''+    // sets CPU flags and stores in CCC the number 
    'FZ=(RA=='+R+');'+  // of cpu cycles needed 
    'FN=1;'+ 
    'FC=RA<'+R+';'+ 
    'FH=(RA&0x0F)<('+R+'&0x0F);'+ 
    'ICC='+C+';'; 
} 

Używanie „makro”, więc kod generowany jest „w locie” i nie musimy, aby funkcja zwraca do niego lub napisać dużo kodu powtórzyć dla każdego istruction ...

OP[0xB8]=new Function(CPU_CP_A('RB',4)); // CP B 
OP[0xB9]=new Function(CPU_CP_A('RC',4)); // CP C 
OP[0xBA]=new Function(CPU_CP_A('RD',4)); // CP D 
OP[0xBB]=new Function(CPU_CP_A('RE',4)); // CP E 
OP[0xBC]=new Function('T1=HL>>8;'+CPU_CP_A('T1',4)); // CP H 
OP[0xBD]=new Function('T1=HL&0xFF;'+CPU_CP_A('T1',4)); // CP L 
OP[0xBE]=new Function('T1=MEM[HL];'+CPU_CP_A('T1',8)); // CP (HL) 
OP[0xBF]=new Function(CPU_CP_A('RA',4)); // CP A 

teraz w e może wykonać kod emulowane tak:

OP[MEM[PC]](); // MEM is an array of bytes and PC the program counter 

Nadzieja to pomaga ...

+2

Czy kod źródłowy emulatora jest dostępny w dowolnym miejscu? –

+1

'nowa funkcja (ciąg)' jest kontekstem 'eval()' i jako taka ma takie same cechy wydajności 'eval()' – Havvy

+1

Nie sądzę, że to prawda. Może to być eval, ale eval występuje tylko raz. Gdy jest to funkcja, powinna wykonywać się dowolną liczbę razy z normalną prędkością funkcji. –

3
function unless(condition,body) { 
    return 'if(! '+condition.toSource()+'()) {' + body.toSource()+'(); }'; 
} 


eval(unless(function() { 
    return false; 
    }, function() { 
    alert("OK"); 
})); 
+0

Nie jest to zły pomysł, ale niestety rozwiązanie dodaje zbyt wiele definicji funkcji eval i 2x. +1 za próbę. –

+1

Makra są rozwijane w czasie KOMPILACJI, więc musimy dodać etap kompilacji do JavaScript lub zapomnieć o makrach. Możemy skompilować JavaScript przez wywołanie tylko do funkcji eval(), więc i tak potrzebujemy eval(). –

+0

makro to cukier syntaktyczny dla większej spójności i ekspresji kodu. Nie zwiększają one teoretycznie rodzaju rzeczy, które możesz zrobić, czy nie. Są one wydawane jednorazowo podczas kompilacji, co powoduje, że koszt runtime wynosi zero. Przykład tutaj nie powiodło się: eval będzie wywoływany za każdym razem, a kod jest bardziej szczegółowy i mniej czytelny niż w przypadku bezpośredniego napisania równoważnego javascriptu. Aby makra były przydatne, powinieneś być w stanie używać go ze składnią, na przykład chyba ("false", "alert (" OK ")"); –

10

Można też teraz używać ClojureScript skompilować Clojure do javascript i uzyskać w ten sposób makr. Uwaga ClojureScript używa Google Closure.

5

LispyScript jest najnowszym językiem, który kompiluje do Javascript, który obsługuje makra. Ma składnię Lisp jak drzewo, ale także zachowuje tę samą semantykę Javascript. Nota prawna: Jestem autorem LispyScript.

+0

Czy LispyScript jest językiem homoiconic (takim jak Scheme i Common Lisp)? –

+0

Tak LispyScript jest homoiconic. Zobacz dokumentację tutaj. http://lispyscript.com – Santosh

+0

Czy LispyScript jest w jakikolwiek sposób powiązany z ParenScript? Wyglądają bardzo podobnie do mnie, ponieważ oba dialekty Lisp kompilują się do JavaScript. http://common-lisp.net/project/parenscript/ –

20

Biblioteka przez Mozillę (tzw SweetJS) przeznaczony jest do symulacji makr w języku JavaScript. Na przykład możesz użyć SweetJS, aby zamienić słowo kluczowe function na def.

Powiązane problemy