Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
rubyish; 2.x like named parameters
  • Loading branch information
dwarring committed Dec 26, 2013
1 parent 9466ff0 commit 8e407b3
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 40 deletions.
5 changes: 3 additions & 2 deletions examples/rubyish/README.md
Expand Up @@ -22,7 +22,7 @@ Implemented:
- a couple of methods: `.call` and `.nil?`
- infixish assignments: `+=` `-=` `*=` ...
- simple classes and objects with attributes.
- inheritance (no mixins yet) - see [inheritance.t](t/inheritance.t)
- method inheritance (no mixins yet) - see [inheritance.t](t/inheritance.t)
- `while` and `until` loops
- statement modifiers `if` `unless`, `while`, `until` e.g.: `puts 42 if true`
- basic arrays and hashes
Expand All @@ -32,7 +32,8 @@ Implemented:
- lightweight eRuby like templating, see [template.rbi](examples-rubyish/template.rbi)
- heredocs, literal `<<EOF ... EOF` and interpolating `<<"END" ... END`
- code block arguments `even = grep(arr) {|n| n % 2 == 0}` -- see [functional.t](t/functional.t)
- package constants `Trig::PI = 3.1415926`
- package constants `Trig::PI = 3.1415926` (no inheritance yet)
- ruby 2.x named parameters: def foo(bar:42, baz:) ; bar ^ baz; end

Notes:
------
Expand Down
90 changes: 52 additions & 38 deletions examples/rubyish/rubyish.nqp
Expand Up @@ -21,8 +21,8 @@ class RubyishClassHOW {
}

method add_method($obj, $name, $code) {
nqp::die("This class already has a method named " ~ $name)
if nqp::existskey(%!methods, $name);
nqp::die("This class already has a method named " ~ $name)
if nqp::existskey(%!methods, $name);

%!methods{$name} := $code;
}
Expand Down Expand Up @@ -103,15 +103,13 @@ grammar Rubyish::Grammar is HLL::Grammar {

rule signature {
:my $*IN_PARENS := 1;
[[ <param> ]+ % ',' [ ',' '*' <slurpy=.param> ]? [ ',' '&' <func=.param> ]?
| '*' <slurpy=.param>] [ ',' '&' <func=.param> ]?
| '&' <func=.param>
[ <param> | '*' <slurpy=.param> | '&' <func=.param> ] +% ','
}

token param {
<ident> [:s<hs> '=' <EXPR>]? {
%*SYM{~$<ident>} := 'var'
}
token param {:s<hs>
<ident> [ $<named>=':' <EXPR>? | '=' <EXPR> ]? {
%*SYM{~$<ident>} := 'var'
}
}

token stmt:sym<class> {
Expand Down Expand Up @@ -158,7 +156,7 @@ grammar Rubyish::Grammar is HLL::Grammar {
token term:sym<call> {
<!keyword>
<operation> ['(' ~ ')' <call-args=.paren-args>? <code-block>?
|:s<hs> <call-args>? <?{callable(~$<operation>)}>
|:s<hs> <?{callable(~$<operation>)}> <call-args>?
]
}

Expand All @@ -181,13 +179,15 @@ grammar Rubyish::Grammar is HLL::Grammar {
}

token call-args {:s<hs>
[ <arg=.hash-args>||<arg=.EXPR>]+ % ',' [ ',' <arg=.func-ref> ]?
| <arg=.func-ref>
[ <arg> ] +% ','
}

token func-ref { '&' <arg=.EXPR> }
proto token arg {*}

token hash-args {:s [ <EXPR> '=>' <EXPR> ]+ % ',' }
token arg:sym<expr> {:s <EXPR> <!before ['=>'|':']> }
token arg:sym<func> { '&' <EXPR> }
token arg:sym<keyw> { <ident> ':' <EXPR> }
token arg:sym<hash> {:s [ <EXPR> '=>' <EXPR> ]+ % ',' }

token paren-args {:my $*IN_PARENS := 1; <call-args> }

Expand All @@ -201,8 +201,8 @@ grammar Rubyish::Grammar is HLL::Grammar {
:my $*MAYBE_DECL := 0;
\+?
[$<sigil>=[ \$ | \@\@? ] | <pkg=.ident>'::'<?before <[A..Z]>> | <!keyword> ]
<ident><!before [\!|\?|\h*\(]>
[ <?before \h* '=' [\w | \h+ || <.EXPR>] { $*MAYBE_DECL := 1 }> || <?> ]
<ident><!before [\!|\?|<hs>\(]>
[ <?before <hs> <bind-op> { $*MAYBE_DECL := 1 }> || <?> ]
}

token term:sym<var> { <var> }
Expand Down Expand Up @@ -248,7 +248,7 @@ grammar Rubyish::Grammar is HLL::Grammar {

# Interpolation
token interp { '#{' ~ '}' [:s<hs> [ <stmtlist> ]
|| <panic('string interpolation error')>]
|| <panic('string interpolation error')>]
}
token quote_escape:sym<#{ }> { <interp> }

Expand Down Expand Up @@ -344,15 +344,16 @@ grammar Rubyish::Grammar is HLL::Grammar {
':' <O('%conditional, :reducecheck<ternary>, :op<if>')>
}

token infix:sym<=> { <sym><![>]> <O('%assignment, :op<bind>')> }
token bind-op {'='<![>]>}
token infix:sym<=> { <.bind-op> <O('%assignment, :op<bind>')> }

token prefix:sym<not> { <sym> <O('%loose_not, :op<not_i>')> }
token infix:sym<and> { <sym> <O('%loose_logical, :op<if>')> }
token infix:sym<or> { <sym> <O('%loose_logical, :op<unless>')> }

# Parenthesis
token circumfix:sym<( )> { :my $*IN_PARENS := 1;
'(' <EXPR> ')' <O('%methodop')> }
'(' ~ ')' <EXPR> <O('%methodop')> }

# Method call
token postfix:sym<.> {
Expand Down Expand Up @@ -490,7 +491,7 @@ class Rubyish::Actions is HLL::Actions {
my $call;

if $op {
$call := QAST::Op.new( :op($op) )
$call := QAST::Op.new( :op($op) )
}
elsif %*SYM{$name} eq 'method' && $*DEF {
$call := QAST::Op.new( :op('callmethod'),
Expand Down Expand Up @@ -550,11 +551,21 @@ class Rubyish::Actions is HLL::Actions {
make @args;
}

method func-ref($/) {
make $<arg>.ast
method arg:sym<expr>($/) {
make $<EXPR>.ast
}

method hash-args($/) {
method arg:sym<func>($/) {
make $<EXPR>.ast
}

method arg:sym<keyw>($/) {
my $arg := $<EXPR>.ast;
$arg.named( ~$<ident> );
make $arg;
}

method arg:sym<hash>($/) {
my $args := QAST::Op.new( :op<hash> );

$args.push( $_.ast )
Expand Down Expand Up @@ -624,18 +635,18 @@ class Rubyish::Actions is HLL::Actions {
);
}
else {
my $ns;
if $<pkg> {
$ns := ~$<pkg>;
}
elsif !$sigil && $*IN_CLASS {
# could be a package constant
my $c := nqp::substr($name, 0, 1);
$ns := $*CLASS_BLOCK.name
if $c ge 'A' && $c le 'Z';
}
$name := $ns ~ '::' ~ $name
if $ns;
my $ns;
if $<pkg> {
$ns := ~$<pkg>;
}
elsif !$sigil && $*IN_CLASS {
# could be a package constant
my $c := nqp::substr($name, 0, 1);
$ns := $*CLASS_BLOCK.name
if $c ge 'A' && $c le 'Z';
}
$name := $ns ~ '::' ~ $name
if $ns;

if $*MAYBE_DECL {

Expand Down Expand Up @@ -706,6 +717,9 @@ class Rubyish::Actions is HLL::Actions {
my $var := QAST::Var.new(
:name(~$<ident>), :scope('lexical'), :decl('param')
);
$var.named(~$<ident>)
if $<named>;

$*CUR_BLOCK.symbol('self', :declared(1));

$var.default( $<EXPR>.ast )
Expand All @@ -723,7 +737,7 @@ class Rubyish::Actions is HLL::Actions {
}

if $<slurpy> {
@params.push($<slurpy>.ast);
@params.push($<slurpy>[0].ast);
@params[-1].slurpy(1);
}

Expand Down Expand Up @@ -752,8 +766,8 @@ class Rubyish::Actions is HLL::Actions {
);

$new_type.push( QAST::SVal.new( :value(~$<classbody><super>),
:named('isa') ) )
if $<classbody><super>;
:named('isa') ) )
if $<classbody><super>;

$class_stmts.push(QAST::Op.new(
:op('bind'),
Expand Down
10 changes: 10 additions & 0 deletions examples/rubyish/t/params.t
@@ -0,0 +1,10 @@
puts "1..5"
def foo(offset:0,desc:,test=1)
puts "ok #{test+offset} - #{desc}"
end

foo(desc:"postional default")
foo(2, desc:"positional - named last")
foo(desc:"positional - named first", 3)
foo(2, desc:"positional + two named params",offset:2)
foo(offset:3, 2, desc:"named + positional (middle)")

0 comments on commit 8e407b3

Please sign in to comment.