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)

James Long

May 30, 2014
Tweet

More Decks by James Long

Other Decks in Technology

Transcript

  1. Macros
    Unshackling JavaScript
    James Long / @jlongster
    with

    View Slide

  2. View Slide

  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
    ==

    View Slide

  4. 1998
    EcmaScript 2

    View Slide

  5. 1999
    EcmaScript 3

    View Slide

  6. View Slide

  7. View Slide

  8. 2014
    EcmaScript 6

    View Slide

  9. var {x, y} = pos;

    View Slide

  10. <3

    COMPILERS

    View Slide

  11. View Slide

  12. @jlongster

    View Slide

  13. (lisp)

    View Slide

  14. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  18. View Slide

  19. EmojiScript

    View Slide

  20. Emotion as a Value

    View Slide

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

    View Slide

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

    View Slide

  23. View Slide

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

    View Slide

  25. > === true

    View Slide

  26. if(1 == “1”) { ... }!
    // Error: "==" is not allowed
    # Enforce Good Practices

    View Slide

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

    View Slide

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

    View Slide

  29. # Errors
    "something is wrong"

    View Slide

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

    View Slide

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

    View Slide

  32. # Better Expressiveness
    if(user < ) {!
    "be happy"!
    }

    View Slide

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

    View Slide

  34. View Slide

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

    View Slide

  36. View Slide

  37. macros/fat-arrow.js
    x => x * x
    function(x) {!
    return x * x;!
    }.bind(this)

    View Slide

  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];

    View Slide

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

    View Slide

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

    }

    View Slide

  41. $ sjs!
    -m emojiscript/macros/poop.js !
    -m es6-macros/macros/fat-arrow.js!
    file.js

    View Slide

  42. Experiment!

    View Slide

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

    View Slide

  44. View Slide

  45. View Slide


  46. View Slide

  47. View Slide

  48. View Slide

  49. @Inject(TodoList)!
    export class AppView extends View {!
    !
    constructor(todos) {!
    this.todos = todos;!
    //...!
    }!
    !
    // ...!
    !
    }
    # Angular & ES6+

    View Slide

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

    View Slide

  51. macro macro {!
    case { $ctx } => {!
    throwSyntaxError(!
    "macros are not allowed, go home”,!
    #{$ctx}!
    );!
    }!
    }

    View Slide

  52. # Function Tracing

    View Slide

  53. 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;!
    }!
    }

    View Slide

  54. $('#app').html('');

    View Slide

  55. # Stack Allocation

    View Slide

  56. 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);

    View Slide

  57. defineRecord Point {!
    x : double,!
    y : double!
    }!
    !
    Point pos;!
    pos.x = 100;!
    pos.y = 80;

    View Slide

  58. var ptr = SP;!
    SP -= 16;!
    F8[ptr + 0] = 100;!
    F8[ptr + 8] = 80;

    View Slide

  59. ?

    View Slide

  60. # Sweet.js Features
    • Pattern Matching
    • Various expansion strategies
    • Hygiene

    View Slide

  61. # 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!
    }!
    }

    View Slide

  62. # Expansion Strategies: rule
    macro foo {!
    rule { } => {!
    // expanded code!
    }!
    !
    rule { } => {!
    // expanded code!
    }!
    !
    rule { } => {!
    // expanded code!
    }!
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  67. # Expansion Strategies: case
    !
    macro foo {!
    case { $ctx } => {!
    // any JavaScript executed here!!
    !
    if(!cond) {!
    throwSyntaxError("bad thing!", #{$ctx});!
    }!
    !
    letstx $name = [token];!
    return #{!
    // expanded code here!
    $name!
    }!
    }!
    }

    View Slide

  68. # 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

    View Slide

  69. # Syntax Highlighting

    View Slide

  70. View Slide

  71. # 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

    View Slide

  72. Thanks!
    James Long / @jlongster
    https://github.com/jlongster/emojiscript

    View Slide