{"id":76,"date":"2005-02-22T00:16:21","date_gmt":"2005-02-21T22:16:21","guid":{"rendered":"http:\/\/blogs.bl0rg.net\/netzstaub\/?p=76"},"modified":"2005-02-22T00:16:21","modified_gmt":"2005-02-21T22:16:21","slug":"lisp-nach-javascript","status":"publish","type":"post","link":"https:\/\/blogs.bl0rg.net\/netzstaub\/2005\/02\/22\/lisp-nach-javascript\/","title":{"rendered":"Lisp nach Javascript"},"content":{"rendered":"<p>\nWegen unkontrollierbarem, auswucherndem Idlen heute nur ein kleiner Einblick in die Konvertierung von <a href=\"http:\/\/en.wikipedia.org\/wiki\/Lisp_programming_language\">Lisp<\/a> nach Javascript.\n<\/p>\n<p>\n<img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blogs.bl0rg.net\/netzstaub\/images\/klammeraffe.jpg\" height=\"174\" width=\"209\" border=\"1\" align=\"middle\" hspace=\"4\" vspace=\"4\" alt=\"Klammeraffe\" \/>\n<\/p>\n<p>\nEin nettes Feature bei Lisp sind die Klammern. Ja, die Klammern, diese kleinen Rattenschw&#228;nze die die meisten Leute zuerst abturnen, wenn sie Lisp-Code sehen. &#8220;Ieeh, das ist ja unlesbar, wie soll man sich da zurechtfinden?&#8221;. Das dachte auch <a href=\"http:\/\/www-formal.stanford.edu\/jmc\/\">John McCarthy<\/a> bei der Entwicklung von Lisp, und hatte eigentlich fest eingeplant, da sp&#228;ter mal eine &#8220;normale&#8221; Infixe Syntax dr&#252;ber zu kippen. Doch wichtiger war zuerst &#252;berhaupt eine funktionnierende Implementierung, und die benutzte intern wie praktisch jede andere Programmiersprache einen abstrakten Syntaxbaum (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Abstract_syntax_tree\">AST &#8211; Abstract Syntax Tree<\/a>), das man auf einem &#8220;linearen&#8221; Medium wie Text einfach durch Postfixausdr&#252;cke niederschreiben kann. Bei Lisp waren das die SEXPs (S-Expression, ich glaube das S steht f&#252;r Syntax). Doch diese SEXPs erwiesen sich als ungemein praktisch, weil sie eigentlich selber Listen sind. Und die Liste ist der primitive Datentyp von Lisp (LISP heisst ja auch nichts anderes als LISt Processing). Das heisst, das man in Lisp ohne grosse H&#252;rden Lisp-Code manipulieren kann. Klingt nach wilden Voodo-Opfer-Parties im dunklen Bayou, und ich will auch nicht verschweigen, dass es manchmal auch so ist. Aber in der Praxis heisst das dann meistens folgendes:\n<\/p>\n<ul>\n<li>Fehlt ein Konstrukt in der Sprache, l&#228;sst es sich einfach herbeizaubern<\/li>\n<li>Will man Lisp-Code oder sowas &#228;hnliches transformieren, braucht man keinen Parser und Lexer und Compiler zu schreiben, sondern man wirft einfach ein paar Lisp-Funktionen und noch 2-3 Makros zum abrunden und fertig ist die Software.<\/li>\n<\/ul>\n<p>\nWie das genau funktionniert l&#228;sst sich ganz sch&#246;n anhand des folgenden Beispiels zeigen. Angenommen, man hat eine Webplattform, die in Lisp geschrieben ist. Die Plattform generiert dynamisch Webseiten, die aus HTML bestehen. In den meisten Programmiersprachen macht man das mit einem Wust von &#8220;print&#8221;-Statements, in LISP schreibt man 1 Makro und brauch nur noch Listen zu generieren. Kleiner Einblick:\n<\/p>\n<p>\nDieses Macro definiert die Spezialform, um ein CMS-internen Link zu erzeugen.\n<\/p>\n<pre>(defmacro cmslink (url &#38;body body)\n  `(html ((:a :class \"cmslink\" :href ,url)\n          ,@body)))\n<\/pre>\n<p>\nWenn man jetzt aber Javascript noch einf&#252;hren will, dann wird das ganz sch&#246;n anstrengend, denn so einfach geformt wie HTML ist javascript nun wieder nicht. Aber auf ganz viele &#8220;print&#8221;, bzw FORMAT Aufrufe zur&#252;ckzugreifen, ne, wirklich, das geh&#246;rt sich nicht. Und den Javascript-Code aufzutrennen in zus&#228;tzliche Dateien ist je nachdem auch ein bisschen zuviel Aufwand. Und was ist, wenn Javascript-Code dynamisch generiert werden soll, z.B. um Inhalte aus der Datenbank &#8220;effizient&#8221; in Javascript zu mappen (anstatt jetzt wilde XML\/RPC Orgien in javascript zu veranstalten). Nun, ein komplizierte Sprache ist Javascript nicht wirklich, man k&#246;nnte doch sowas &#228;hnliches wie <a href=\"http:\/\/www.evaluator.pt\/download.html\">Linj<\/a> bauen. Linj ist eine Art &#8220;Compiler&#8221;, der eine Lisp-&#228;hnliche Sprache nach lesbarem Java konvertiert. Lisp-&#228;hnlich heisst hier eher sowas wie ein &#8220;Subset&#8221; von Lisp, was nach Java &#8220;umgewandelt&#8221; wird. Also nix mit Compilen nach Java-Bytecode, sondern Java-Quellcode, und Quellcode den man noch lesen kann. Der Ansatz ist hier praktisch alle Java-Konstrukte in Lisp nachzumodellieren, bzw. die Lisp-Konstrukte wie DO, DEFUN, usw&#8230; nach Java umzuwandeln.\n<\/p>\n<p>\nDer erste Schritt ist hier die Variablennennung, die bei Javascript vielleicht noch wichtiger ist, weil Javascript meistens sehr sehr viel auf die schon existierenden Element im DOM-Baum zur&#252;ckgreift. Problem ist, Lisp (oder zumindest der Lisp-Reader) ist case-insensitive. Wenn ich also foObAr oder FOOBAR oder fooBar oder foobar schreibe, der Lisp-Reader macht daraus immer FOOBAR. Wenn ich jetzt wirklich mit camelCase was machen will, dann muss ich mir da echt M&#252;he geben, und z.B. |camelCase| schreiben, also &#252;berall so kleine h&#228;ssliche Pipes reinbauen. Das ist auch keinem Entwickler (oder Entwicklerin) zumutbar, da muss was anderes her. Da hab ich mir was ganz ungeniert bei Linj abgeschaut. Bei Linj wird die LISP-&#252;bliche Variablen und Funktionsnennung nach Java konvertiert, bzw. andersrum: getFoobar in Java wird da zu get-foobar in Lisp. Die Konstante +MAX-SIZE+ in Lisp wird zu MAXSIZE in Java, WTF?#! in Lisp wird zu WTFQuestionHashBang in Java. Um das zu machen bedarf es ein bisschen Magie, die ich hier mal *hust* erl&#228;utern werde. Ach ja, der Code hier ist nicht wirklich fein, nicht wirklich bugfrei, nicht wirklich getestet, aber ich wollte ja heute noch unbedingt etwas posten:\n<\/p>\n<pre>\n(defvar *special-chars*\n  '((#\\! . \"Bang\")\n    (#\\? . \"What\")\n    (#\\# . \"Hash\")\n    (#\\@ . \"At\")\n    (#\\% . \"Percent\")\n    (#\\+ . \"Plus\")))\n\n(defun string-chars (string)\n  (coerce string 'list))\n\n(defun constant-string-p (string)\n  (let ((len (length string))\n        (constant-chars '(#\\+ #\\*)))\n    (and (&gt; len 2)\n         (member (char string 0) constant-chars)\n         (member (char string (1- len)) constant-chars))))\n\n(defun symbol-to-js (symbol)\n  (when (symbolp symbol)\n    (setf symbol (symbol-name symbol)))\n  (let (res\n        (lowercase t)\n        (all-uppercase nil))\n    (when (constant-string-p symbol)\n      (setf all-uppercase t\n            symbol (subseq symbol 1 (1- (length symbol)))))\n    (flet ((reschar (c)\n             (push (if (and lowercase (not all-uppercase))\n                       (char-downcase c)\n                       (char-upcase c)) res)\n             (setf lowercase t)))\n      (dotimes (i (length symbol))\n        (let ((c (char symbol i)))\n          (case c\n            (#\\- (setf lowercase (not lowercase)))\n            ('(#\\! #\\? #\\+ #\\$ #\\@ #\\# #\\%)\n             (dolist (i (coerce (cdr (assoc c *special-chars*)) 'list))\n               (reschar i)))\n            (t (reschar c))))))\n    (coerce (nreverse res) 'string)))\n\n<\/pre>\n<p>\nAls erstes haben wir hier eine Assoziationsliste namens *SPECIAL-CHARS*, die die Zuweisung von &#8220;schr&#228;gen&#8221; Buchstaben in Lispnotation zu ihrem verbosen Bloat&#228;quivalent in Javascript festh&#228;lt. Eine Assoziationsliste ist so etwas wie ein &#8220;Poor Man&#8217;s Hash-Table&#8221;, in Lisp gibt es da eine Funktion ASSOC mit der man da einfach drinsuchen kann. Weiter geht&#8217;s mit der Funktion STRING-CHARS, die ein String zu einer Listen von Buchstaben konvertiert, eigentlich nur da weil mich das Rumgehampel mit COERCE genervt hat, es gibt da aber bestimmt bessere Wege, &#252;ber ein String zu iterieren. Die Funktion CONSTANT-STRING-P guckt eigentlich nur nach, ob der vorliegende String in Lispnotation sowas wie eine &#8220;Lisp-Konstante&#8221; ist, also sowas wie +KONSTANTE+ oder *KONSTANTE*. Das -P am Ende der Funktion steht f&#252;r &#8220;Predicate&#8221; und heisst, dass CONSTANT-STRING-P irgendwas auf Wahrheit &#252;berpr&#252;ft (in dem Fall ob der String eine Konstante nennt), und T (f&#252;r Wahr) oder NIL (f&#252;r Falsch) zur&#252;ckgibt. So, und SYMBOL-TO-JS ist das Prachtst&#252;ck, und ich bin gerade zu m&#252;de, um diesen Bloatcode zu erkl&#228;ren, gehe deshalb jetzt schlafen, und mache morgen weiter. In der Zeit d&#252;rft ihr ja untersuchen, was da genau passiert. Wer ineffiziente Gr&#252;tze findet darf sie ja gerne behalten, oder vielleicht ein bisschen in die Kommentare unten schmieren (die jetzt wieder gehen m&#252;ssten, und vor Blinden und Spammern effektiv gesch&#252;tzt sind durch MT Secure Code).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wegen unkontrollierbarem, auswucherndem Idlen heute nur ein kleiner Einblick in die Konvertierung von Lisp nach Javascript. Ein nettes Feature bei Lisp sind die Klammern. Ja, die Klammern, diese kleinen Rattenschw&#228;nze die die meisten Leute zuerst abturnen, wenn sie Lisp-Code sehen. &hellip; <a href=\"https:\/\/blogs.bl0rg.net\/netzstaub\/2005\/02\/22\/lisp-nach-javascript\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-76","post","type-post","status-publish","format-standard","hentry","category-lispstaub"],"_links":{"self":[{"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/posts\/76","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/comments?post=76"}],"version-history":[{"count":0,"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/posts\/76\/revisions"}],"wp:attachment":[{"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/media?parent=76"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/categories?post=76"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.bl0rg.net\/netzstaub\/wp-json\/wp\/v2\/tags?post=76"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}