+ - 0:00:00
Notes for current slide
Notes for next slide

Informal Domain Specific Languages
with Perl 6

Brian Duggan

bduggan
bduggan@matatu.org

1 / 71

We craft software for companies that care about the details.

2 / 71
Informal Domain Specific Languages

Introduction

  • not talking about HTML, SQL, CSS
  • but about languages that generate things like HTML, SQL, CSS
  • informal: "unofficial", "casual", expressive, colloquial
  • lack rigorous specifications
  • practical
3 / 71
Informal Domain Specific Languages

Examples

  • HTML Generation (templates, wikis)
    • Template Toolkit, Jinja2, Slim
    • Markdown, Wikitext (Wikipedia)
  • SQL Generation
    • DBIx::Class, Rose::DB, SQLAlchemy, Arel
  • Web Microframeworks
    • Mojolicious, Dancer, Plack, Sinatra
4 / 71
Informal Domain Specific Languages

Categories

  • Internal: subset of a general language 1
    web frameworks, ORMs
  • External: parsed 1
    templating, wikis
  • Variant: modification
    "Slangs"

    1DSLs, Fowler, 2010

5 / 71

We have three broad classifications, but as we'll see in Perl 6, the distinction can be murky. Internal may look like variants. Variants are handled in a similar manner to external DSLs.

Informal Domain Specific Languages

Techniques

  • Internal: subset of a general language Custom operators
    web frameworks, ORMs
  • External: parsed Grammars
    templating, wikis
  • Variant: modification Slangs
    "Slangs"
6 / 71

For the rest of this talk, we'll look at few general techniques from each category and apply them to a few specific examples.

Internal IDSLs

Custom Operators

7 / 71
Perl 6 Custom Operators

operator types

  • infix: A + B
  • prefix: -A
  • postfix: A++
  • circumfix: [A]
  • post-circumfix: A[B]
8 / 71
Perl 6 Custom Operators

operator types

  • infix: A + B
  • prefix: -A
  • postfix: A++
  • circumfix: [A]
  • post-circumfix: A[B]
  • Unary operators take 1 argument
  • Binary operators take 2 arguments
8 / 71
Perl 6 Custom Operators

operator types

  • infix: A + B
  • prefix: -A
  • postfix: A++
  • circumfix: [A]
  • post-circumfix: A[B]
  • Unary operators take 1 argument
  • Binary operators take 2 arguments
  • Infix operators also have a noun form, &[+]
say &[+](1,2)
8 / 71
Perl 6 Custom Operators

operator types

  • infix: A + B
  • prefix: -A
  • postfix: A++
  • circumfix: [A]
  • post-circumfix: A[B]
  • Unary operators take 1 argument
  • Binary operators take 2 arguments
  • Infix operators also have a noun form, &[+]
say &[+](1,2)
  • Subs that take two args can be used as infix binary operators
sub plus-twice($a,$b) { $a + 2 * $b }
say 1 [&plus-twice] 2
8 / 71
Perl 6 Custom Operators

Custom operators

Custom operators are declared like this:

sub infix:<plus>($x,$y) {
$x + $y
}
say 1 plus 2;
9 / 71
Perl 6 Custom Operators

Custom operators

Custom operators are declared like this:

sub infix:<plus>($x,$y) {
$x + $y
}
say 1 plus 2;
3
9 / 71
Perl 6 Custom Operators

Custom operators

Custom operators are declared like this:

sub infix:<plus>($x,$y) {
$x + $y
}
say 1 plus 2;
3
sub prefix:<@@>($x) { $x * 2 }
sub postfix:<+++>($y is rw) { $y+=3 }
my $z = @@10;
$z+++;
say $z;
9 / 71
Perl 6 Custom Operators

Custom operators

Custom operators are declared like this:

sub infix:<plus>($x,$y) {
$x + $y
}
say 1 plus 2;
3
sub prefix:<@@>($x) { $x * 2 }
sub postfix:<+++>($y is rw) { $y+=3 }
my $z = @@10;
$z+++;
say $z;
23
9 / 71
Perl 6 Custom Operators

Custom operators

  • All of unicode is fair game

# dot product
sub infix:<∙>(@a,@b) {
return [+] @a Z* @b
}
say (1,2) ∙ (3,4)
10 / 71
Perl 6 Custom Operators

Custom operators

  • All of unicode is fair game

# dot product
sub infix:<∙>(@a,@b) {
return [+] @a Z* @b
}
say (1,2) ∙ (3,4)
11
10 / 71
Perl 6 Custom Operators

Custom operators

  • All of unicode is fair game
sub circumfix:<⌊ ⌋>($x) {
$x.floor
}
say2.4
11 / 71
Perl 6 Custom Operators

Custom operators

  • All of unicode is fair game
sub circumfix:<⌊ ⌋>($x) {
$x.floor
}
say2.4
2
11 / 71
Perl 6 Custom Operators

Combining operators

sub infix:<plus>($x,$y) {
$x + $y
}
sub infix:<times>($x,$y) {
$x * $y
}
say 1 plus 2 times 3;
12 / 71
Perl 6 Custom Operators

Combining operators

sub infix:<plus>($x,$y) {
$x + $y
}
sub infix:<times>($x,$y) {
$x * $y
}
say 1 plus 2 times 3;
9
12 / 71

But multiplication has higher precedence than addition. We want this to be 7.

Perl 6 Custom Operators

Precedence

is tighter controls precedence

sub infix:<plus>($x,$y) {
$x + $y
}
sub infix:<times>($x,$y) is tighter(&infix:<plus>) {
$x * $y
}
say 1 plus 2 times 3;
13 / 71
Perl 6 Custom Operators

Precedence

is tighter controls precedence

sub infix:<plus>($x,$y) {
$x + $y
}
sub infix:<times>($x,$y) is tighter(&infix:<plus>) {
$x * $y
}
say 1 plus 2 times 3;
7

Also is looser, is equiv

13 / 71
Perl 6 Custom Operators

Chaining operators

sub infix:<to-the-power>($x,$y) {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
14 / 71
Perl 6 Custom Operators

Chaining operators

sub infix:<to-the-power>($x,$y) {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
64
14 / 71
Perl 6 Custom Operators

Chaining operators

sub infix:<to-the-power>($x,$y) {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
64
232 treated as (23)2 but should be 2(32)
14 / 71
Perl 6 Custom Operators

associativity

We can fix this. is assoc!

sub infix:<to-the-power>($x,$y) is assoc<right> {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
15 / 71
Perl 6 Custom Operators

associativity

We can fix this. is assoc!

sub infix:<to-the-power>($x,$y) is assoc<right> {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
512
15 / 71
Perl 6 Custom Operators

associativity

We can fix this. is assoc!

sub infix:<to-the-power>($x,$y) is assoc<right> {
$x ** $y
}
say 2 to-the-power 3 to-the-power 2
512

Associativity types:
right
left
non
chain (1 < 2 < 3)
list (1,2 X 3,4 X 5,6)

15 / 71
Perl 6 Custom Operators

argument types

define subtraction between strings

sub infix:<->($x,$y) {
$x.subst($y, "", :g);
}
say "house" - "u";
16 / 71
Perl 6 Custom Operators

argument types

define subtraction between strings

sub infix:<->($x,$y) {
$x.subst($y, "", :g);
}
say "house" - "u";
"hose"
16 / 71
Perl 6 Custom Operators

argument types

define subtraction between strings

sub infix:<->($x,$y) {
$x.subst($y, "", :g);
}
say "house" - "u";
"hose"

But

say 32 - 2
16 / 71
Perl 6 Custom Operators

argument types

define subtraction between strings

sub infix:<->($x,$y) {
$x.subst($y, "", :g);
}
say "house" - "u";
"hose"

But

say 32 - 2
3
16 / 71
Perl 6 Custom Operators

argument types

define subtraction between strings

sub infix:<->($x,$y) {
$x.subst($y, "", :g);
}
say "house" - "u";
"hose"

But

say 32 - 2
3

Argh!

16 / 71
Perl 6 Custom Operators

multiple dispatch

We can fix this, too.

multi infix:<->(Str $x, Str $y) {
$x.subst($y, "", :g);
}
say "house" - "u";
say 32 - 3;
17 / 71
Perl 6 Custom Operators

multiple dispatch

We can fix this, too.

multi infix:<->(Str $x, Str $y) {
$x.subst($y, "", :g);
}
say "house" - "u";
say 32 - 3;
hose
29
17 / 71
Perl 6 Custom Operators

multiple dispatch

Also works for strings, ints, constants, or any class.

multi sub infix:<->(Str $x, Str $y) {
$x.subst($y, "", :g);
}
multi sub infix:<->(Str $x, Int $y) {
$x.substr(0,$x.chars-$y)
}
multi sub infix:<->("escalator","electricity") {
"stairs"
}
say "catamaran" - "a";
say "catamaran" - 6;
say "escalator" - "electricity";
say 10 - 5;
18 / 71
Perl 6 Custom Operators

multiple dispatch

Also works for strings, ints, constants, or any class.

multi sub infix:<->(Str $x, Str $y) {
$x.subst($y, "", :g);
}
multi sub infix:<->(Str $x, Int $y) {
$x.substr(0,$x.chars-$y)
}
multi sub infix:<->("escalator","electricity") {
"stairs"
}
say "catamaran" - "a";
say "catamaran" - 6;
say "escalator" - "electricity";
say 10 - 5;
ctmrn
cat
stairs
5
18 / 71
Perl 6 Custom Operators

example

emulate python % operator

multi sub infix:<%>(Str $f, Numeric $n) {
return sprintf($f,$n)
}
multi sub infix:<%>(Str $f,List $l) {
return sprintf($f,$l.flat)
}
say 'This is %d.' % 40;
say 'Pi is about %0.2f and e is about %0.2f' % ( π, e );
19 / 71

Custom operators are an "internal" language, but may look like a variant

Perl 6 Custom Operators

example

emulate python % operator

multi sub infix:<%>(Str $f, Numeric $n) {
return sprintf($f,$n)
}
multi sub infix:<%>(Str $f,List $l) {
return sprintf($f,$l.flat)
}
say 'This is %d.' % 40;
say 'Pi is about %0.2f and e is about %0.2f' % ( π, e );
This is 40.
Pi is about 3.14 and e is about 2.72
19 / 71

Custom operators are an "internal" language, but may look like a variant

Perl 6 Custom Operators

example: generating SQL

  • DBIx::Class, Rose::DB::Object, SQL::Abtract
  • SQLAlchemy, Squeel
  • Typical techniques:
    • method chaining
    • operator overloading
    • data structure abuse
20 / 71
Perl 6 Custom Operators

example: generating SQL

  • DBIx::Class, Rose::DB::Object, SQL::Abtract
  • SQLAlchemy, Squeel
  • Typical techniques:
    • method chaining
    • operator overloading
    • data structure abuse

Perl 6 operators add new techniques:

SELECT id
FROM user INNER JOIN address ON address.user=user.id
WHERE name = 'ed' and fullname='Ed Jones'
(User + Address)[ name == 'ed' and fullname == 'Ed Jones' ]
  • native operators and, == can be defined for columns
  • post-circumfix [ ] can be used to filter
20 / 71
Perl 6 Custom Operators

example: generating SQL

(User + Address)[ name == 'ed' and fullname == 'Ed Jones' ]
class Table { ... }
multi sub infix:<+>(Table $a, Table $b) {
...
}
21 / 71
Perl 6 Custom Operators

example: generating SQL

(User + Address)[ name == 'ed' and fullname == 'Ed Jones' ]
class Filter { ... }
class Column { ... }
multi sub infix:<==>(Column $a, $b) {
...
return Filter.new( ... )
}
multi sub infix:<and>(Filter $a, Filter $b) {
...
return Filter.new( ... )
}
22 / 71

Though as far as operators and SQL go, there is already a precedent. The mathematical foundation of SQL is relational algebra.

Perl 6 Custom Operators

example: generating SQL

Relational algebra

  • Created by E.F. Codd in 70s
  • Mathematical foundation of SQL
  • Defines operators such as:
    • Projection (π)
    • Selection (σ)
    • Rename (ρ)
    • Natural join (⋈)
    • Semijoin (⋉)(⋊)
    • Antijoin (▷)
    • Division (÷)
    • Left outer join (⟕)
    • Right outer join (⟖)
23 / 71
Perl 6 Custom Operators

example: an ORM

Relational algebra

sub infix:<⋈>($a, $b) {
"$a NATURAL JOIN $b"
}
say "users""addresses"
users NATURAL JOIN addresses
sub prefix:<∏>(@x) {
"SELECT " ~ @x.join(', ')
}
say ∏<name age>;
SELECT name, age

Conclusion: Custom operators are useful building blocks for internal informal DSLs.

24 / 71

External IDSLs

Grammars

25 / 71

half way: 20 minutes

Grammars

HTML Generation

  • Templating
    • Template Toolkit, Jinja2, Slim
    • about 100 listed on wikipedia
  • Wikis
    • Markdown, MediaWiki
    • 15 "lightweight markup language" listed wikipedia

Let's look at how to use grammars to parse one of them.

26 / 71
Grammars

Slim
http://slim-lang.com

Looks like this:

html
head
title Slim Examples
body
h1 Markup examples

generates

<html>
<head>
<title>Slim Examples</title>
</head>
<body>
<h1>Markup examples</h1>
</body>
</html>
27 / 71
Grammars

Parsing Slim

  1. Parse
  2. Build a DOM
28 / 71
Grammars

Parsing Slim

  • A grammar is a collection of regexes (like a class + methods)
  • A token is a regex with no backtracking
  • A rule is a regex with significant whitespace
grammar slim {
rule TOP { <line>+ %% <eol>}
token line { <indentation> <tag> [ ' ' <text> ]? }
token indentation { <indent>* }
token indent { ' ' }
token tag { \w+ }
token text { \V+ }
token eol { \n+ }
}
say slim.parse(q:to/DONE/);
html
head
title Slim Examples
body
h1 Markup Examples
DONE
  • X %% Y means [ X ][ Y X ]*
29 / 71
Grammars

Parsing Slim

html
head
title Slim Examples
body
h1 Markup examples
grammar slim {
rule TOP { <line>+ %% <eol> }
token line {
<indentation>
<tag> [ ' ' <text> ]?
}
token indentation { <indent>* }
token indent { ' ' }
token tag { \w+ }
token text { \V+ }
}
line => 「html
tag => 「html」
indentation => 「」
line => 「 head」
tag => 「head」
indentation => 「 」
indent => 「 」
line => 「 title Slim Examples」
tag => 「title」
text => 「Slim Examples」
indentation => 「 」
indent => 「 」
indent => 「 」
...

A grammar generates a match object.

30 / 71
Grammars

Generating a DOM

  • A grammar can be associated with an object, to perform "actions".
  • Methods on the object have the same names as the regexes in the grammar.
  • When a regex is reached, the method is called.
31 / 71
Grammars

Generating a DOM

  • A grammar can be associated with an object, to perform "actions".
  • Methods on the object have the same names as the regexes in the grammar.
  • When a regex is reached, the method is called.
  • Let's make a class called "DOM" and make an instance.
grammar slim {
token tag { ... }
token text { ... }
token indentation { ... }
...
}
class DOM {
method tag { ... }
method text { ... }
method indentation { ... }
}
my $dom = DOM.new;
slim.parse($text, actions => $dom);

31 / 71
Grammars

Generating a DOM

Algorithm:

  1. Make a Node class which has a parent node + child nodes.
    The nodes will be the DOM tree. Also we will need a stack.
  2. When you see a tag, push a new node onto the stack.
  3. When you see text, set the text of the top node.
  4. When you see indentation, pop until the stack size is the level of indentation.
  5. Connect parent + child nodes when moving from the stack to the tree.

Tag: push.
Indentation: maybe pop.

32 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 0, stack 0: push

33 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 0, stack 0: push

34 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 1: push

35 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 1: push

36 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 2, stack 2: push

37 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 2, stack 2: push

38 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 3: pop 3-1=2 then push

39 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 3: pop 3-1=2 then push

40 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 3: pop 3-1=2 then push

41 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 3: pop 3-1=2 then push

42 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 1, stack 3: pop 3-1=2 then push

43 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 2, stack 2: push

44 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent 2, stack 2: push

45 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent: 0, stack 3: pop 3-0-3

46 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent: 0, stack 3: pop 3-0-3

47 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent: 0, stack 3: pop 3-0-3

48 / 71
Grammars

stack

tree

0 html
1 head
2 title Slim Examples
1 body
2 h1 Markup examples
0

indent: 0, stack 3: pop 3-0-3

49 / 71
Grammars

The Code

  1. Make a Node class which has a parent node + child nodes.
    The nodes will be the DOM tree. Also we will need a stack.
class Node {
has Str $.tag;
has Str $.text is rw;
has Node $.parent is rw;
has Node @.children;
}
class DOM {
my Node @stack;
has Node $.tree;
method tag { ... }
method text { ... }
method indentation { ... }
}
grammar slim {
...
token tag { ... }
token text { ... }
token indentation { ... }
}
50 / 71
Grammars

The Code

1. When you see a tag, push a new node onto the stack.

method tag($/) {
@stack.push: Node.new: tag => ~$/;
}

2. When you see text, set the text of the top node.

method text($/) {
@stack[*-1].text = ~$/;
}

$/ is the match object for the token
~ stringifies

51 / 71
Grammars

The Code

3. When you see indentation, pop until the stack size is the level of indentation.
4. Connect parent + child nodes when moving from the stack to the tree.

method indentation($/) {
while @stack > @$<indent> {
my $node = @stack.pop;
with @stack[*-1] -> $top {
$node.parent = $top;
$top.children.push: $node;
}
}
}

$/ is the match object for the indentation token
with checks for definedness

52 / 71
Grammars

The Code

To print, dump a node, and recursively dump children at one more level of indentation.

class Node {
...
method dump(:$level=0) {
say "<$.tag>".indent($level);
say .indent($level) with $.text;
.dump(level => $level+1) for self.children;
say "</$.tag>".indent($level);
}
}

.indent on a string prepends spaces
A leading . calls a method on $_

53 / 71
Grammars

The Code

grammar slim {
rule TOP { <line>+ %% <eol>}
token line { <indentation> <tag> [ ' ' <text> ]? }
token indentation { <indent>* }
token indent { ' ' }
token tag { \w+ }
token text { \V+ }
token eol { \n+ }
}
class Node {
has Str $.tag;
has Str $.text is rw;
has Node $.parent is rw;
has Node @.children;
method dump(:$level=0) {
say "<$.tag>".indent($level);
say $.text.indent($level) with $.text;
.dump(level => $level+1) for self.children;
say "</$.tag>".indent($level);
}
}
class DOM {
my Node @stack;
has Node $.top;
method tag($/) {
@stack.push: Node.new: tag => ~$/;
$!top //= @stack[0];
}
method text($/) {
@stack[*-1].text = ~$/;
}
method indentation($/) {
while @stack > @$<indent> {
my $node = @stack.pop;
with @stack[*-1] -> $top {
$node.parent = $top;
$top.children.push: $node;
}
}
}
}
my $dom = DOM.new;
my $match = slim.parse(q:to/DONE/,actions => $dom) or die 'no parse';
html
head
title Slim Examples
body
h1 Markup Examples
DONE
$dom.top.dump;
54 / 71
Grammars

Output:

<html>
<head>
<title>
Slim Examples
</title>
</head>
<body>
<h1>
Markup Examples
</h1>
</body>
</html>

Conclusion: Grammars are useful for parsing external informal DSLs.

55 / 71

Variant IDSLs

Slangs

56 / 71
Slangs

Variants

  • Modifying a language to create a new language
  • Perl 5 source filters: bad, messy
  • Perl 6 slangs provide a structured way to do this
57 / 71
Slangs

Slangs

  • Rakudo uses NQP (Not Quite Perl) to build Perl 6
  • NQP defines Perl6::Grammar and Perl6::Actions
  • slang is short for sublanguage 1
  • i.e. a language derived from Perl6::Grammar
  • (or derived from another grammar in the Perl 6 language braid)
  • slangs are "A principled way to create DSLs" 1

1 design.perl6.org

58 / 71
Slangs

Slangs

  • Still WIP
  • What works now:
    • Modifying grammars (at compile time)
    • Updating the language braid
    • Lexically scoped slangs
59 / 71
Slangs

The language braid

  • During compilation, the %*LANG variable, has grammars and actions.
  • Interwoven and combined, they form Perl 6.
BEGIN {
for sort keys %*LANG -> $k {
say "$k is { %*LANG{$k}.^name }"
}
}
MAIN is Perl6::Grammar
MAIN-actions is Perl6::Actions
P5Regex is Perl6::P5RegexGrammar
P5Regex-actions is Perl6::P5RegexActions
Quote is Perl6::QGrammar
Quote-actions is Perl6::QActions
Regex is Perl6::RegexGrammar
Regex-actions is Perl6::RegexActions
60 / 71
Slangs

The language braid

  • Immutable versions are stored in $~MAIN, $~Quote, etc
  • Available even at run time
for $~MAIN, $~Quote, $~P5Regex, $~Regex {
say .grammar.^name;
say .actions.^name;
}
Perl6::Grammar
Perl6::Actions
Perl6::P5RegexGrammar
Perl6::P5RegexActions
Perl6::QGrammar
Perl6::QActions
Perl6::RegexGrammar
Perl6::RegexActions
61 / 71
Slangs

Perl6::Grammar

To see examples, use --target=parse:

perl6 --target=parse -e "say 'hello, world'"
62 / 71
Slangs

Perl6::Grammar

To see examples, use --target=parse:

perl6 --target=parse -e "say 'hello, world'"
- statementlist: say 'hello, world'
- statement: 1 matches
- EXPR: say 'hello, world'
- longname: say
- name: say
- identifier: say
- args: 'hello, world'
- arglist: 'hello, world'
- EXPR: 'hello, world'
- value: 'hello, world'
- quote: 'hello, world'
- nibble: hello, world
62 / 71
Slangs

Perl6::Grammar

grammar Perl6::Grammar {
rule statementlist { ... <statement> ... }
token statement { ... <EXPR> ... }
token longname { ... <name> .. }
token name { ... <identifier> ... }
token identifier { ... }
...
}
63 / 71
Slangs

Making a slang

Let's try to make a slang in which subroutines are declared like:

lambda foo() { ... }

instead of

sub foo() { ... }
64 / 71
Slangs

Making a slang

Original (Perl6/Grammar.nqp)

token routine_declarator:sym<sub> {
'sub' <.end_keyword> <routine_def('sub')>
}
  • Let's change 'sub' to 'lambda'.

  • Deriving from a class and applying a role gives us a way to have a new class with a single method replaced.

  • Deriving from a grammar and applying a role gives us a way to have a new grammar with a single token replaced.

65 / 71
Slangs

Making a slang

but creates a copy of an object, with a role mixed in.

66 / 71
Slangs

Making a slang

but creates a copy of an object, with a role mixed in.

BEGIN {
%*LANG<MAIN> := $~MAIN.grammar but role {
rule routine_declarator:sym<sub> {
'lambda' <.end_keyword> <routine_def('sub')>
}
}
}
66 / 71
Slangs

Making a slang

but creates a copy of an object, with a role mixed in.

BEGIN {
%*LANG<MAIN> := $~MAIN.grammar but role {
rule routine_declarator:sym<sub> {
'lambda' <.end_keyword> <routine_def('sub')>
}
}
}
lambda foo { say 'hello, world' }
foo();
66 / 71
Slangs

Lexically scoped slangs

If you put your slang in a module:

# lambda.pm
sub EXPORT {
%*LANG<MAIN> := $~MAIN but role { ... }
}

Using it is lexically scoped:

{
use lambda;
lambda hello { say 'hi' }
}
## lambda bye { say 'bye' } # illegal!
sub bye { say 'bye' } # ok
67 / 71
Slangs

Examples

a few slangs on modules.perl6.org

  • Slang::SQL -- sql inline in Perl 6
  • Slang::Piersing -- allow identifier names ending in ? or !
  • Slang::Tuxic -- allow a space betwen sub and parameter list (sub ($x))
68 / 71
Slangs

future?

  • Specified but not yet implemented
  • augment slang, supercede slang
augment slang MAIN { ... }
supercede slang Regex { ... }
69 / 71

Conclusion

  • Making informal DSLs may involve
    • creative use of syntax (internal)
    • parsing (external)
    • modifying an existing language (variant)
  • Perl 6 offers new and exciting techniques for each of these.
70 / 71

fin

71 / 71

We craft software for companies that care about the details.

2 / 71
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow
```