Skip to content

Commit

Permalink
Change CommonEnum et al to be a role
Browse files Browse the repository at this point in the history
  • Loading branch information
sorear committed Jan 20, 2012
1 parent b3cb68b commit 98c7c82
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 23 deletions.
45 changes: 22 additions & 23 deletions lib/CORE.setting
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,21 @@ my class Cool {
}
}
my class Nil is Cool {
method new() { Nil }
method iterator() { ().iterator }
method gist() { 'Nil' }
method Str() { '' }
method flat() { self.iterator.flat }
method list() { self.iterator.list }
method postcircumfix:<[ ]>(\$key) { @(self).[$key] }
method at_pos($key) { @(self).[$key] }
method Capture () { ().Capture }
method elems () { 0 }
method Numeric() { 0 }
method Bool () { ?0 }
}

my role Positional { Any }
my role Associative { Any }

Expand Down Expand Up @@ -894,8 +909,7 @@ my class ClassHOW {
} }
}
# These should be refactored as roles once those become available
my class CommonEnum {
my role CommonEnum {
has $!index;
method perl() {
Expand Down Expand Up @@ -931,29 +945,29 @@ my class CommonEnum {
method roll($count = 1) { self.enums.map({ self.($_.key) }).roll($count) }
}
my class IntBasedEnum is CommonEnum {
my role IntBasedEnum does CommonEnum {
method Numeric() { Q:CgOp { (box Int (unbox int (@ {self}))) } }
method Int() { self.Numeric }
method Str() { defined(self) ?? self.key !! nextsame }
method Stringy() { defined(self) ?? self.key !! nextsame }
method _create($ix,$val) { Q:CgOp {
(letn obj (box (@ {self}) (unbox int (@ {$val.Int})))
(setslot CommonEnum $!index (@ (l obj)) {$ix.Int})
(setslot (obj_llhow (@ (l obj))) $!index (@ (l obj)) {$ix.Int})
(l obj))
} }
}
my class StrBasedEnum is CommonEnum {
my role StrBasedEnum does CommonEnum {
method _create($ix,$val) { Q:CgOp {
(letn obj (box (@ {self}) (unbox str (@ {$val.Str})))
(setslot CommonEnum $!index (@ (l obj)) {$ix.Int})
(setslot (obj_llhow (@ (l obj))) $!index (@ (l obj)) {$ix.Int})
(l obj))
} }
}
# Using the "enum" type declarator would require a compile time reference
# to the EnumMap type, which depends on Bool; ick.
my class Bool is IntBasedEnum is Int {
my class Bool is Int does IntBasedEnum {
our $_enums;
method enums() { $_enums }
our constant True = Q:CgOp { (box Bool (bool 1)) };
Expand Down Expand Up @@ -1204,21 +1218,6 @@ sub hash(|$cap) {
my class EMPTY { }
my class Nil is Cool {
method new() { Nil }
method iterator() { ().iterator }
method gist() { 'Nil' }
method Str() { '' }
method flat() { self.iterator.flat }
method list() { self.iterator.list }
method postcircumfix:<[ ]>(\$key) { @(self).[$key] }
method at_pos($key) { @(self).[$key] }
method Capture () { ().Capture }
method elems () { 0 }
method Numeric() { 0 }
method Bool () { False }
}
my class Parcel is Cool does Positional {
method ACCEPTS(\$what) { defined(self) ?? self.flat.ACCEPTS($what) !! nextsame }
method flat() { self.iterator.flat }
Expand Down Expand Up @@ -2573,7 +2572,7 @@ multi sub exp($x) { $x.exp }
multi sub exp($x, $base) { $base ** $x }
# 'Order' type
my class Order is IntBasedEnum is Int {
my class Order is Int does IntBasedEnum {
our $_enums;
method enums() { $_enums }
our constant Increase = -1;
Expand Down
88 changes: 88 additions & 0 deletions src/niecza
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,94 @@ method statement_prefix:BEGIN ($/) {
$con.init = True;
make $con;
}
method type_declarator:enum ($/) {
my $scope = $*SCOPE || 'our';

my @exports;
for map *.ast, @$<trait> -> $t {
if $t<export> {
push @exports, @( $t<export> );
} else {
$/.CURSOR.sorry("Unsupported enum trait $t.keys()");
}
}

my @pairs = self.trivial_eval($/, $<term>.ast);
my $last = -1;
my ($has_ints, $has_strs);
for @pairs {
if $_ !~~ Pair {
my $key = $_;
my $value = $last.succ;
$_ = $key => $value;
}
given $last = .value {
when Int { $has_ints = True; }
when Str { $has_strs = True; }
default { $/.CURSOR.sorry("Enum values must be Int or Str"); }
}
}
if $has_ints && $has_strs {
$/.CURSOR.sorry("Enum may not contain both Int and Str values");
}

my ($basetype) = self.process_name($*OFTYPE<longname>);
$basetype //= $*CURLEX<!sub>.compile_get_pkg('CORE', $has_strs ?? 'Str' !! 'Int');
my $kindtype = $has_strs ?? 'StrBasedEnum' !! 'IntBasedEnum';

if $<name> && $<name>.reduced eq 'longname' && $scope ne 'anon' {
# Longnamed enum is a kind of type definition

my ($lexvar, $obj);
$/.CURSOR.trymop({
($lexvar, $obj) = self.do_new_package($/, :$scope,
class => 'class', name => $<longname>, :@exports);

$obj.add_super($basetype);
$obj.add_role($*CURLEX<!sub>.compile_get_pkg($kindtype));

my $nb = $*unit.create_sub(
outer => $*CURLEX<!sub>,
name => $obj.name ~ '.enums',
cur_pkg => $*CURLEX<!sub>.cur_pkg,
class => 'Method');

$nb.set_transparent;

my $nbvar = self.gensym;
$nb.add_my_name('self', noinit => True);
$nb.set_signature($Sig.simple('self'));
$nb.finish(self.init_constant(
self.make_constant($/, 'anon', Any),
$OpCallMethod.new(name => 'new',
receiver => mklex($/, 'EnumMap'), args => [$<term>.ast])));
$*CURLEX<!sub>.create_static_pad;
$*CURLEX<!sub>.add_my_sub($nbvar, $nb, |mnode($/));
$obj.add_method(0, 'enums', $nb, |mnode($/));
$obj.close;

for @pairs {
self.make_constant_into($/, $obj, .key, rhs =>
$OpCallSub.new(invocant => mklex($/, $lexvar),
args => [ $OpStringLiteral.new(text => .key) ]));
}

for @pairs {
self.init_constant(self.make_constant($/, $scope, .key),
$OpCallSub.new(invocant => mklex($/, $lexvar),
args => [ $OpStringLiteral.new(text => .key) ]));
}
});

make mklex($/, $lexvar);
} else {
make self.init_constant(
self.make_constant($/, $<name> ?? $scope !! 'anon', ~$<name>),
$OpCallMethod.new(pos=>$/, name => 'new',
receiver => mklex($/, 'EnumMap'),
args => [$<term>.ast])),
}
}

}

Expand Down

0 comments on commit 98c7c82

Please sign in to comment.