Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unshackling JavaScript with Macros

Unshackling JavaScript with Macros

My JSConf 2014 talk (not so useful without speaker notes. video coming soon)

6bb149ad2abfeb95fc367813910ba35e?s=128

James Long

May 30, 2014
Tweet

Transcript

  1. Macros Unshackling JavaScript James Long / @jlongster with

  2. None
  3. with http://www.quirkyscience.com/wp-content/uploads/2012/06/Explosion-Image-by-US-Department-of-Defense.jpg ASI http://markakiprof.files.wordpress.com/2009/11/stresss.jpg ==

  4. 1998 EcmaScript 2

  5. 1999 EcmaScript 3

  6. None
  7. None
  8. 2014 EcmaScript 6

  9. var {x, y} = pos;

  10. <3
 COMPILERS

  11. None
  12. @jlongster

  13. (lisp)

  14. None
  15. (defmacro if (test cons alt)! ...)

  16. (defmethod (ship :speed) ()! (sqrt (+ (^ x-velocity 2)! (^

    y-velocity 2)))
  17. method ship speed() {! return sqrt(pow(this.xVelocity, 2),! pow(this.yVelocity, 2));! }

  18. None
  19. EmojiScript

  20. Emotion as a Value

  21. var happy = ;! // ILLEGAL # Emotion Literals

  22. var happy = ;! // OK! # Emotion Literals

  23. None
  24. # Emotional Algebra + == ; + == + ==

    ;
  25. > === true

  26. if(1 == “1”) { ... }! // Error: "==" is

    not allowed # Enforce Good Practices
  27. # Enforce Good Practices if(1 “1”) { ... }

  28. # Errors throw new Error(! “something is wrong”! )

  29. # Errors "something is wrong"

  30. # Automatic Cat Insertion var foo = 1 + 2;!

    var bar = baz();! var user = + ;
  31. # Automatic Cat Insertion var foo = 1 + 2!

    var bar = baz()! var user = +
  32. # Better Expressiveness if(user < ) {! "be happy"! }

  33. $ npm install emojiscript $ emo file.js > output.js

  34. None
  35. $ npm install emojiscript $ sjs -m emojiscript/macros/poop.js file.js

  36. None
  37. macros/fat-arrow.js x => x * x function(x) {! return x

    * x;! }.bind(this)
  38. macros/destructure.js var {x, y} = obj;! var [one, two] =

    arr; var x = obj.x;! var y = obj.y;! var one = arr[0];! var two = arr[1];
  39. macros/class.js class Foo {! move(x, y) {! this.x = x;!

    this.y = y;! }! }
  40. macros/class.js function Foo() {}! Foo.prototype.move = function(x, y) {! this.x

    = x;! this.y = y;
 }
  41. $ sjs! -m emojiscript/macros/poop.js ! -m es6-macros/macros/fat-arrow.js! file.js

  42. Experiment!

  43. • Proposal • Discussion • Finalization • Implementation • Maturation

  44. None
  45. None
  46. None
  47. None
  48. @Inject(TodoList)! export class AppView extends View {! ! constructor(todos) {!

    this.todos = todos;! //...! }! ! // ...! ! } # Angular & ES6+
  49. macro == {! case { $ctx } => {! throwSyntaxError(!

    "== is not allowed”,! #{$ctx}! );! }! }
  50. macro macro {! case { $ctx } => {! throwSyntaxError(!

    "macros are not allowed, go home”,! #{$ctx}! );! }! }
  51. # Function Tracing

  52. let function = macro {! rule { $name($args ...) {

    $body ... } } => {! console.log(! "calling " + syntaxToString $name + “..”! );! ! var ret = (function($args ...) {! $body ...;! })($args ...);! ! console.log(! "returning " + syntaxToString $name! );! return ret;! }! }
  53. $('#app').html('<div class="box"></div>');

  54. # Stack Allocation

  55. var MB = 1024 * 1024;! var STACK_SIZE = 2

    * MB;! var buffer = new ArrayBuffer(STACK_SIZE);! var U1 = new Uint8Array(buffer);! var I1 = new Int8Array(buffer);! var U2 = new Uint16Array(buffer);! var I2 = new Int16Array(buffer);! var U4 = new Uint32Array(buffer);! var I4 = new Int32Array(buffer);! var F4 = new Float32Array(buffer);! var F8 = new Float64Array(buffer);
  56. defineRecord Point {! x : double,! y : double! }!

    ! Point pos;! pos.x = 100;! pos.y = 80;
  57. var ptr = SP;! SP -= 16;! F8[ptr + 0]

    = 100;! F8[ptr + 8] = 80;
  58. ?

  59. # Sweet.js Features • Pattern Matching • Various expansion strategies

    • Hygiene
  60. # Pattern Matching macro var {! rule { { $name

    (,) ... } = $obj } => {! var $($name = $obj.$name) (,) ...! }! ! rule { [ $name (,) ... ] = $arr } => {! var i = 0;! var $($name = $arr[i++]) (,) ...! }! ! rule { $name } => {! var $name! }! }
  61. # Expansion Strategies: rule macro foo {! rule { <pattern1>

    } => {! // expanded code! }! ! rule { <pattern2> } => {! // expanded code! }! ! rule { <pattern3> } => {! // expanded code! }! }
  62. # Expansion Strategies: let let var = macro {! rule

    { $name = $val:expr } => {! var $name = $val! }! }
  63. # Expansion Strategies: infix macro => {! rule infix {

    ($value (,) ...) | {$body ...} } => {! function($value (,) ...) {! $body ...! }.bind(this)! }! rule infix { ($value (,) ...) | $guard:expr } => {! function($value (,) ...) {! return $guard;! }.bind(this)! }! }!
  64. # Expansion Strategies: operator operator + 12 left { $l,

    $r } => #{! add($l, $r)! } add(add(add(1, 2), 3), 4); 1 + 2 + 3 + 4
  65. # Expansion Strategies: operator operator + 12 right { $l,

    $r } => #{! add($l, $r)! } add(1, add(2, add(3, 4))) 1 + 2 + 3 + 4
  66. # Expansion Strategies: case ! macro foo {! case {

    $ctx <pattern1> } => {! // any JavaScript executed here!! ! if(!cond) {! throwSyntaxError("bad thing!", #{$ctx});! }! ! letstx $name = [token];! return #{! // expanded code here! $name! }! }! }
  67. # Hygiene macro square {! rule { $expr:expr } =>

    {! var x = $expr;! x * x! }! }! ! var x = 5;! square x; var x$1 = 5;! var x$2 = x$1;! x$2 * x$2
  68. # Syntax Highlighting

  69. None
  70. # Quick Recap • JavaScript is under a lot of

    pressure to
 evolve • sweet.js provides macros for adding language features as libraries • Compilers can’t work together • We can help TC39 and liberate JavaScript
  71. Thanks! James Long / @jlongster https://github.com/jlongster/emojiscript