pug - a compiler pipeline

33

Upload: forbes-lindesay

Post on 15-Apr-2017

649 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Pug - a compiler pipeline
Page 2: Pug - a compiler pipeline

HTML Output<article> <h1>Title</h1> <p>Body</p></article>

Page 3: Pug - a compiler pipeline

Pug Sourcearticle h1 Title p Body

Page 4: Pug - a compiler pipeline

Pug Compiler

Lexer Parser Code Gen

Page 5: Pug - a compiler pipeline

Lexerarticle h1 Title p Body

• tag – "article"• indent• tag – "h1"• text – "Title"• new line• tag – "p"• text – "Body"• outdent

Page 6: Pug - a compiler pipeline

Lexerclass Lexer { constructor(str) { this.str = str; this.indent = 0; }}

Page 7: Pug - a compiler pipeline

Lexertag() { let match = /^[a-z]+/.exec(this.str); if (match) { this.str = this.str.substr(match[0].length); return {type: 'tag', val: match[0]}; }}

Page 8: Pug - a compiler pipeline

Lexertext() { let match = /^ .+/.exec(this.str); if (match) { this.str = this.str.substr(match[0].length); return {type: 'text', val: match[0].substr(1)}; }}

Page 9: Pug - a compiler pipeline

Lexernewline() { let match = /^\n( *)/.exec(this.str); if (match) { this.str = this.str.substr(match[0].length); let oldIndent = this.indent; this.indent = match[1].length; if (this.indent > oldIndent) return {type: 'indent'}; if (this.indent < oldIndent) return {type: 'outdent'}; return {type: 'newline'}; }}

Page 10: Pug - a compiler pipeline

Lexerfail() { throw new Error( 'Unexpected text' );}

getTokens() { let tokens = []; while (this.str.length) { tokens.push( this.newline() || this.tag() || this.text() || this.fail() ); } tokens.push({type: 'eos'}); return tokens;}

Page 11: Pug - a compiler pipeline

Parser

OutdentIndent NewLine

Text"Body"

Tag"h1"

Tag"article"

Text"Title"

Tag"p"

Page 12: Pug - a compiler pipeline

Parser

Text"Body"

Tag"h1"

Tag"article"

Text"Title"

Tag"p"

Page 13: Pug - a compiler pipeline

Parserclass Parser { constructor(tokens) { this.tokens = new TokenStream(tokens); }}

Page 14: Pug - a compiler pipeline

Token Stream• Next – get the next token and advance the stream• Peek – get the next token without advancing the stream• Expect(type) – get the next token and advance the stream

Page 15: Pug - a compiler pipeline

ParserparseFile() { let nodes = []; while (this.tokens.peek().type !== 'eos') { if (this.tokens.peek().type === 'tag') { nodes.push(this.parseTag()); } else { this.tokens.expect('newline'); } } this.tokens.expect('eos'); return {type: 'File', nodes};}

Page 16: Pug - a compiler pipeline

ParserparseTag() { let tok = this.tokens.expect('tag'); let body = null; switch (this.tokens.peek().type) { case 'text': body = this.parseText(); break; case 'indent': body = this.parseBlock(); break; } return {type: 'Tag', name: tok.val, body};}

Page 17: Pug - a compiler pipeline

ParserparseBlock() { this.tokens.expect('indent'); let nodes = []; while (this.tokens.peek().type !== 'outdent') { if (this.tokens.peek().type === 'tag') { nodes.push(this.parseTag()); } else { this.tokens.expect('newline'); } } this.tokens.expect('outdent'); return {type: 'Block', nodes};}

Page 18: Pug - a compiler pipeline

Code Gen

Text"Body"

Tag"h1"

Tag"article"

Text"Title"

Tag"p"

Page 19: Pug - a compiler pipeline

Code Gen

Text"Body"

Tag"h1"

Tag"article"

"Title"

Tag"p"

Page 20: Pug - a compiler pipeline

Code Gen

Text"Body"

"<h1>Title</h1>"

Tag"article"

Tag"p"

Page 21: Pug - a compiler pipeline

Code Gen

"Body"

"<h1>Title</h1>"

Tag"article"

Tag"p"

Page 22: Pug - a compiler pipeline

Code Gen

"<h1>Title</h1>"

Tag"article"

"<p>Body</p>"

Page 23: Pug - a compiler pipeline

Code Gen "<article><h1>Title</h1><p>Body</p></article>"

Page 24: Pug - a compiler pipeline

Code Genfunction render(node) { switch (node.type) { case 'Block': return renderBlock(node); case 'Tag': return renderTag(node); case 'Text': return renderText(node); }}

Page 25: Pug - a compiler pipeline

Code Genfunction renderBlock(node) { return node.nodes.map(render).join('\n');}

Page 26: Pug - a compiler pipeline

Code Genfunction renderTag(node) { if (!node.body) return '<' + node.name + '/>'; return ( '<' + node.name + '>' + render(node.body) + '</' + node.name + '>' );}

Page 27: Pug - a compiler pipeline

Code Genfunction renderText(node) { return node.val;}

Page 28: Pug - a compiler pipeline

Pug Compiler

Lexer Parser Code Gen

Page 29: Pug - a compiler pipeline

Includesarticle h1 Title include ./content.pug

Page 30: Pug - a compiler pipeline

LinkingFile A

IncludeFile B

FILE B

Page 31: Pug - a compiler pipeline

LinkingFile A

IncludeFile BFILE B

Page 32: Pug - a compiler pipeline

Pug Compiler Pipeline

Lexer Parser Loader Linker Code-Gen

String Tokens AST Collection of ASTs

AST String

Page 33: Pug - a compiler pipeline

Lexer Parser Loader Linker Code-Gen

Now it's your turn!

String Tokens AST Collection of ASTs

AST String