Macros & Sweet.js Prof. Tom Austin San Jos State University - - PowerPoint PPT Presentation

macros sweet js
SMART_READER_LITE
LIVE PREVIEW

Macros & Sweet.js Prof. Tom Austin San Jos State University - - PowerPoint PPT Presentation

CS 252: Advanced Programming Language Principles Macros & Sweet.js Prof. Tom Austin San Jos State University Let's say we want to add classes to JavaScript We'd like to have something like: class Person { constructor(name) {


slide-1
SLIDE 1

CS 252: Advanced Programming Language Principles

  • Prof. Tom Austin

San José State University

Macros & Sweet.js

slide-2
SLIDE 2

Let's say we want to add classes to JavaScript…

slide-3
SLIDE 3

We'd like to have something like:

class Person { constructor(name) { this.name = name; } say(msg) { console.log(this.name + " says: " + msg); } }

slide-4
SLIDE 4

But what we have to type is:

function Person(name) { this.name = name; } Person.prototype.say = function(msg) { console.log(this.name + " says: " + msg); }

slide-5
SLIDE 5

We want to expand our code with classes to a version of JavaScript understood by the interpreter.

Introducing macros…

slide-6
SLIDE 6

What is a macro?

  • Short for macroinstruction.
  • Rule specifies how input sequence

maps to a replacement sequence.

slide-7
SLIDE 7

A Review of Compilers

Lexer/ Tokenizer Parser

source code tokens

Abstract Syntax Tree (AST) Compiler

Machine code

Interpreter

Commands

slide-8
SLIDE 8

Macros in C

  • C preprocessor
  • Text substitution macros

–text is converted to text.

  • Embedded languages are similar

– PHP, Ruby's erb, etc.

slide-9
SLIDE 9

Lexer/ Tokenizer Parser

source code tokens

Abstract Syntax Tree (AST) Compiler

Machine code

Interpreter

Commands

Pre- processor

expanded code

Some variants work at the token level, but the concept is the same.

slide-10
SLIDE 10

C preprocessor example

#define PI 3.14159 #define SWAP(a,b) {int tmp=a;a=b;b=tmp;} int main(void) { int x=4, y=5, diam=7, circum=diam*PI; SWAP(x,y); }

slide-11
SLIDE 11

int main(void) { int x=4, y=5, diam=7, circum=diam*PI; SWAP(x,y); } int main(void) { int x=4, y=5, diam=7, circum=diam*3.14159; {int tmp=x;x=y;y=tmp;}; }

slide-12
SLIDE 12

Problems with C macros

(in class)

slide-13
SLIDE 13

Many macro systems suffer from inadvertent variable capture. Let's look at an example…

slide-14
SLIDE 14

Hygiene

Hygienic macros are macros whose expansion is guaranteed not to cause the accidental capture of identifiers.

slide-15
SLIDE 15

//macro should be on one line #define SWAP(a,b) { int tmp=a; a=b; b=tmp; } int main(void) { int x=4, y=5, tmp=7; SWAP(x,y); // Swaps x&y SWAP(x,tmp); // tmp unchanged }

Why?

slide-16
SLIDE 16

Syntactic macros

  • Work at the level of abstract syntax trees
  • From the Lisp family

–Why Lisp? Because Lisp programs are ASTs

  • Powerful, but expensive
  • Hygiene is still a major concern, but is

perhaps easier to address at that level

slide-17
SLIDE 17

Macro expansion process

Abstract Syntax Tree (AST) Abstract Syntax Tree (AST) Macro Expander Essentially this is a source-to-source compiler

slide-18
SLIDE 18

(define-syntax-rule (swap x y) (let ([tmp x]) (set! x y) (set! y tmp)))

Macros in Racket

slide-19
SLIDE 19

(define-syntax-rule (swap x y) (let ([tmp x]) (set! x y) (set! y tmp)))

Macros in Racket

Pattern

slide-20
SLIDE 20

(define-syntax-rule (swap x y) (let ([tmp x]) (set! x y) (set! y tmp)))

Macros in Racket

Template

slide-21
SLIDE 21

(define-syntax-rule (swap x y) (let ([tmp x]) (set! x y) (set! y tmp))) (let ([a 7][b 3]) (swap a b) (displayln a) (displayln b))

Macros in Racket

slide-22
SLIDE 22

(define-syntax-rule (swap x y) (let ([tmp x]) (set! x y) (set! y tmp))) (let ([a 7][b 3]) (let ([tmp a]) (set! a b) (set! b tmp)) (displayln a) (displayln b))

Expanded code

slide-23
SLIDE 23

Macros for JavaScript

  • No standard macro

system for JavaScript.

  • Sweet.js has been

gaining interest.

  • Recent redesign.
  • http://sweetjs.org/
  • https://www.sweetjs.org/doc/tutorial.html
slide-24
SLIDE 24

Sweet.js high-level

  • Source-to-source compiler for JavaScript.

–Other s2s compilers for JS:

  • TypeScript
  • CoffeeScript
  • Dart (though also has a VM)
  • Project backed by Mozilla
  • Concepts borrowed from Racket
slide-25
SLIDE 25

Prototypal Inheritance

var Droid = { speak: function() { console.log(">>Beep, boop<<, " + "I am " + this.name); }, create: function(name) { var clone = Object.create(this); clone.name = name; return clone; }, };

slide-26
SLIDE 26

var areToo = Droid.create('R2-D2'); but we are used to calling: var bb8 = new Droid('BB8'); We create new droids like so:

slide-27
SLIDE 27

Macro

syntax new = function (ctx) { let ident = ctx.next().value; let params = ctx.next().value; return #`${ident}.create ${params}`; } var bb8 = new Droid('BB8');

slide-28
SLIDE 28

Translated version

var Droid_0 = { speak: function speak() { console.log(">>Beep, boop<<, I am " + this.name); }, create: function create(name_8) { var clone_9 = Object.create(this); clone_9.name = name_8; return clone_9; } }; var bb8_7 = Droid_0.create("BB8");

slide-29
SLIDE 29

Installing Sweet.js

From a Unix/Dos command line: $npm install -g @sweet-js/cli $npm install @sweet-js/helpers

slide-30
SLIDE 30

Invoking Sweet.js

  • Compile your code:

$sjs myfile.js -d out/

  • Then you may run the output file normally:

$node out/myfile.js

slide-31
SLIDE 31

syntax swap = function (ctx) { var a = ctx.next().value; var b = ctx.next().value; return #`var tmp =${a}; ${a}=${b}; ${b}=tmp;`; } var a = 10; var b = 20; console.log("a:" + a + " b:" + b); swap a b; console.log("a:" + a + " b:" + b);

slide-32
SLIDE 32

Iterating over syntax

slide-33
SLIDE 33

syntax square = function (ctx) { var inCtx = ctx.contextify(ctx.next().value); var result = #``; var stx; for (stx of inCtx) { result = result.concat( #`${stx} = ${stx}*${stx};`); inCtx.next(); // Eating comma } return result; } var a = 1; var b = 2; var c = 3; square(a, b, c); console.log("a:"+a+" b:"+b+" c:"+c);

slide-34
SLIDE 34

Output

var a_5 = 1; var b_6 = 2; var c_7 = 3; a_5 = a_5 * a_5; b_6 = b_6 * b_6; c_7 = c_7 * c_7; console.log("a:" + a_5 + " b:" + b_6 + " c:" + c_7);

slide-35
SLIDE 35

Sweet.js helper functions

import { isStringLiteral } from '@sweet-js/helpers' for syntax; syntax m = function(ctx) { if (isStringLiteral(ctx.next().value)) return #`'a string'`; else return #`'not a string'`; } m 'foo'; m 42; var s = "hello"; m s;

slide-36
SLIDE 36

Adding classes to JavaScript. (in class)

slide-37
SLIDE 37

Lab

Create a rotate macro in Sweet.js that works like the swap macro, except that it takes an arbitrary number of arguments. There is no starter code for this lab.