Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'master' of github.com:ekiru/squaak-tutorial
  • Loading branch information
cotto committed Jul 20, 2010
2 parents 3def2bc + b59e109 commit 23c614c
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 43 deletions.
89 changes: 48 additions & 41 deletions doc/tutorial_episode_8.pod
Expand Up @@ -37,8 +37,8 @@ Just as there are integer literals (42) and string literals ("hello world")
that can be assigned to variables, you can have array literals. Below is the
grammar rule for this:

rule array_constructor {
'[' <expression> ** ',' ']'
rule circumfix:sym<[ ]> {
'[' [<EXPR> ** ',']? ']'
}

Some examples are shown below:
Expand All @@ -59,14 +59,21 @@ Besides array literals, Squaak supports hashtable literals, that can be
constructed through a hashtable constructor. The syntax for this is expressed
below:

rule hash_constructor {
'{' <named_field> ** ',' <named_field> '}'
rule circumfix:sym<{ }> {
'{' [<named_field> ** ',']? '}'
}

rule named_field {
<string_constant> '=>' <expression>
<string_constant> '=>' <EXPR>
}

# We need to rename our existing string_constant term to a separate rule
# so that we can use it specifically.
token term:sym<string_constant> { <string_constant> }

# Don't forget to rename the action method.
token string_constant { <quote> }

Some examples are shown below:

foo = {}
Expand Down Expand Up @@ -206,15 +213,19 @@ parameter, Parrot creates an array, while for the named slurpy parameter a
hashtable is created. This happens to be exactly what we need! Implementing
the array and hash constructors becomes trivial:

.sub '!array'
.param pmc fields :slurpy
.return (fields)
.end
# Inset this in src/Squaak/Runtime.pm

.sub '!hash'
.param pmc fields :named :slurpy
.return (fields)
.end
{
my sub array (*@args) { @args; }
my sub hash (*%args) { %args; }

Q:PIR {
$P0 = find_lex 'array'
set_global '!array', $P0
$P0 = find_lex 'hash'
set_global '!hash', $P1
}
}

Array and hashtable constructors can then be compiled into subroutine calls to
the respective Parrot subroutines, passing all fields as arguments. (Note that
Expand All @@ -223,8 +234,8 @@ prevents us from calling these subs in normal Squaak code).

=head2 Basic data types and Aggregates as arguments

All data types, both basic and aggregate data types are represented by Parrot
Magic Cookies (PMCs). The PMC is one of the four built-in data types that Parrot
All data types, both basic and aggregate data types are represented by Polymorphic
Containers (PMCs). The PMC is one of the four built-in data types that Parrot
can handle; the others are integer, floating-point and string. Currently, the
PCT can only generate code to handle PMCs, not the other basic data types.
Parrot has registers for each its four built-in data types. The integer,
Expand Down Expand Up @@ -277,7 +288,7 @@ for hashtables. Implement the action method for key.

=item *

Implement the action methods for array_constructor and hash_constructor. Use a
Implement the action methods for circumfix:sym<[ ]> and circumfix:sym<{ }>. Use a
C<PAST::Op> node and set the pasttype to 'call'. Use the "name" attribute to
specify the names of the subs to be invoked (e.g., C<:name("!array")> ). Note
that all hash fields must be passed as named arguments. Check out PDD26 for
Expand All @@ -302,73 +313,69 @@ Hint: use a C<PAST::Val> node for the string conversion.

=item 1

method key($/) {
my $key := $( $<expression> );
method postfix_expression:sym<key>($/) {
my $key := $<expression>.ast;

make PAST::Var.new( $key, :scope('keyed'),
:vivibase('Hash'),
:viviself('Undef'),
:node($/) );
make PAST::Var.new( $key, :scope('keyed'),
:vivibase('Hash'),
:viviself('Undef'),
:node($/) );
}

=item 2

method term:sym<string_constant>($/) { make $<string_constant>.ast; }

method named_field($/) {
my $past := $( $<expression> );
my $name := $( $<string_constant> );
my $past := $<EXPR>.ast;
my $name := $<string_constant>.ast;
## the passed expression is in fact a named argument,
## use the named() accessor to set that name.
$past.named($name);
make $past;
}

method array_constructor($/) {
method circumfix:sym<[ ]>($/) {
## use the parrot calling conventions to
## create an array,
## using the "anonymous" sub !array
## (which is not a valid Squaak name)
my $past := PAST::Op.new( :name('!array'),
:pasttype('call'),
:node($/) );
for $<expression> {
$past.push($($_));
for $<EXPR> {
$past.push($_.ast);
}
make $past;
}

method hash_constructor($/) {
method circumfix:sym<{ }>($/) {
## use the parrot calling conventions to
## create a hash, using the "anonymous" sub
## !hash (which is not a valid Squaak name)
my $past := PAST::Op.new( :name('!hash'),
:pasttype('call'),
:node($/) );
for $<named_field> {
$past.push($($_));
$past.push($_.ast);
}
make $past;
}

=item 3

rule postfix_expression {
| <key> {*} #= key
| <member> {*} #= member
| <index> {*} #= index
}

rule member {
rule postfix_expression:sym<member> {
'.' <identifier>
{*}
}

method member($/) {
my $member := $( $<identifier> );
method postfix_expression:sym<member>($/) {
my $member := $<identifier>.ast;
## x.y is syntactic sugar for x{"y"},
## so stringify the identifier:
my $key := PAST::Val.new( :returns('String'),
:value($member.name()),
:node($/) );
my $key := PAST::Val.new( :returns('String'),
:value($member.name),
:node($/) );

## the rest of this method is the same
## as method key() above.
Expand Down
64 changes: 63 additions & 1 deletion src/Squaak/Actions.pm
Expand Up @@ -298,6 +298,31 @@ method postfix_expression:sym<index>($/) {
make $past;
}

method postfix_expression:sym<key>($/) {
my $key := $<expression>.ast;

make PAST::Var.new( $key, :scope('keyed'),
:vivibase('Hash'),
:viviself('Undef'),
:node($/) );
}

method postfix_expression:sym<member>($/) {
my $member := $<identifier>.ast;
## x.y is syntactic sugar for x{"y"},
## so stringify the identifier:
my $key := PAST::Val.new( :returns('String'),
:value($member.name),
:node($/) );

## the rest of this method is the same
## as method key() above.
make PAST::Var.new( $key, :scope('keyed'),
:vivibase('Hash'),
:viviself('Undef'),
:node($/) );
}

method identifier($/) {
our @?BLOCK;
my $name := ~$<ident>;
Expand All @@ -320,7 +345,8 @@ method identifier($/) {
method term:sym<integer_constant>($/) {
make PAST::Val.new(:value($<integer>.ast), :returns<Integer>);
}
method term:sym<string_constant>($/) {
method term:sym<string_constant>($/) { make $<string_constant>.ast; }
method string_constant($/) {
make PAST::Val.new(:value($<quote>.ast), :returns<String>);
}
method term:sym<float_constant_long>($/) { # name worksaround lack of LTM
Expand All @@ -331,3 +357,39 @@ method quote:sym<'>($/) { make $<quote_EXPR>.ast; }
method quote:sym<">($/) { make $<quote_EXPR>.ast; }

method circumfix:sym<( )>($/) { make $<EXPR>.ast; }

method named_field($/) {
my $past := $<EXPR>.ast;
my $name := $<string_constant>.ast;
## the passed expression is in fact a named argument,
## use the named() accessor to set that name.
$past.named($name);
make $past;
}

method circumfix:sym<[ ]>($/) {
## use the parrot calling conventions to
## create an array,
## using the "anonymous" sub !array
## (which is not a valid Squaak name)
my $past := PAST::Op.new( :name('!array'),
:pasttype('call'),
:node($/) );
for $<EXPR> {
$past.push($_.ast);
}
make $past;
}

method circumfix:sym<{ }>($/) {
## use the parrot calling conventions to
## create a hash, using the "anonymous" sub
## !hash (which is not a valid Squaak name)
my $past := PAST::Op.new( :name('!hash'),
:pasttype('call'),
:node($/) );
for $<named_field> {
$past.push($_.ast);
}
make $past;
}
17 changes: 16 additions & 1 deletion src/Squaak/Grammar.pm
Expand Up @@ -126,6 +126,8 @@ rule postfix_expression:sym<index> { '[' <EXPR> ']' }

rule postfix_expression:sym<key> { '{' <EXPR> '}' }

rule postfix_expression:sym<member> { '.' <identifier> }

token identifier {
<!keyword> <ident>
}
Expand All @@ -136,7 +138,8 @@ token keyword {
}

token term:sym<integer_constant> { <integer> }
token term:sym<string_constant> { <quote> }
token term:sym<string_constant> { <string_constant> }
token string_constant { <quote> }
token term:sym<float_constant_long> { # longer to work-around lack of LTM
[
| \d+ '.' \d*
Expand All @@ -162,6 +165,18 @@ INIT {

token circumfix:sym<( )> { '(' <.ws> <EXPR> ')' }

rule circumfix:sym<[ ]> {
'[' [<EXPR> ** ',']? ']'
}

rule circumfix:sym<{ }> {
'{' [<named_field> ** ',']? '}'
}

rule named_field {
<string_constant> '=>' <EXPR>
}

token prefix:sym<-> { <sym> <O('%unary-negate, :pirop<neg>')> }
token prefix:sym<not> { <sym> <O('%unary-not, :pirop<isfalse>')> }

Expand Down
12 changes: 12 additions & 0 deletions src/Squaak/Runtime.pm
@@ -1,5 +1,17 @@
# language-specific runtime functions go here

{
my sub array (*@args) { @args; }
my sub hash (*%args) { %args; }

Q:PIR {
$P0 = find_lex 'array'
set_global '!array', $P0
$P0 = find_lex 'hash'
set_global '!hash', $P0
}
}
sub print(*@args) {
pir::print(pir::join('', @args));
1;
Expand Down

0 comments on commit 23c614c

Please sign in to comment.