ljr/wcmtools/s2/S2/NodeProperty.pm

192 lines
5.3 KiB
Perl
Executable File

#!/usr/bin/perl
#
package S2::NodeProperty;
use strict;
use S2::Node;
use S2::NodeNamedType;
use S2::NodePropertyPair;
use vars qw($VERSION @ISA);
$VERSION = '1.0';
@ISA = qw(S2::Node);
sub new {
my ($class) = @_;
my $node = new S2::Node;
$node->{'nt'} = undef;
$node->{'pairs'} = [];
$node->{'builtin'} = 0;
$node->{'use'} = 0;
$node->{'hide'} = 0;
$node->{'uhName'} = undef; # if use or hide, then this is property to use/hide
bless $node, $class;
}
sub canStart {
my ($class, $toker) = @_;
return $toker->peek() == $S2::TokenKeyword::PROPERTY;
}
sub parse {
my ($class, $toker) = @_;
my $n = new S2::NodeProperty;
$n->{'pairs'} = [];
$n->setStart($n->requireToken($toker, $S2::TokenKeyword::PROPERTY));
if ($toker->peek() == $S2::TokenKeyword::BUILTIN) {
$n->{'builtin'} = 1;
$n->eatToken($toker);
}
# parse the use/hide case
if ($toker->peek()->isa('S2::TokenIdent')) {
my $ident = $toker->peek()->getIdent();
if ($ident eq "use" || $ident eq "hide") {
$n->{'use'} = 1 if $ident eq "use";
$n->{'hide'} = 1 if $ident eq "hide";
$n->eatToken($toker);
my $t = $toker->peek();
unless ($t->isa('S2::TokenIdent')) {
S2::error($t, "Expecting identifier after $ident");
}
$n->{'uhName'} = $t->getIdent();
$n->eatToken($toker);
$n->requireToken($toker, $S2::TokenPunct::SCOLON);
return $n;
}
}
$n->addNode($n->{'nt'} = S2::NodeNamedType->parse($toker));
my $t = $toker->peek();
if ($t == $S2::TokenPunct::SCOLON) {
$n->eatToken($toker);
return $n;
}
$n->requireToken($toker, $S2::TokenPunct::LBRACE);
while (S2::NodePropertyPair->canStart($toker)) {
my $pair = S2::NodePropertyPair->parse($toker);
push @{$n->{'tokenlist'}}, $pair;
push @{$n->{'pairs'}}, $pair;
}
$n->requireToken($toker, $S2::TokenPunct::RBRACE);
return $n;
}
sub check {
my ($this, $l, $ck) = @_;
if ($this->{'use'}) {
unless ($l->getType() eq "layout") {
S2::error($this, "Can't declare property usage in non-layout layer");
}
unless ($ck->propertyType($this->{'uhName'})) {
S2::error($this, "Can't declare usage of non-existent property");
}
return;
}
if ($this->{'hide'}) {
unless ($ck->propertyType($this->{'uhName'})) {
S2::error($this, "Can't hide non-existent property");
}
return;
}
my $name = $this->{'nt'}->getName();
my $type = $this->{'nt'}->getType();
if ($l->getType() eq "i18n") {
# FIXME: as a special case, allow an i18n layer to
# to override the 'des' property of a property, so
# that stuff can be translated
return;
}
# only core and layout layers can define properties
unless ($l->isCoreOrLayout()) {
S2::error($this, "Only core and layout layers can define new properties.");
}
# make sure they aren't overriding a property from a lower layer
my $existing = $ck->propertyType($name);
if ($existing && ! $type->equals($existing)) {
S2::error($this, "Can't override property '$name' of type " .
$existing->toString . " with new type " .
$type->toString . ".");
}
my $basetype = $type->baseType;
if (! S2::Type::isPrimitive($basetype) && ! defined $ck->getClass($basetype)) {
S2::error($this, "Can't define a property of an unknown class");
}
# all is well, so register this property with its type
$ck->addProperty($name, $type, $this->{'builtin'});
}
sub asS2 {
my ($this, $o) = @_;
$o->tabwrite("property ");
$o->write("builtin ") if $this->{'builtin'};
if ($this->{'use'} || $this->{'hide'}) {
$o->write("use ") if $this->{'use'};
$o->write("hide ") if $this->{'hide'};
$o->writeln("$this->{'uhName'};");
return;
}
if (@{$this->{'pairs'}}) {
$o->writeln(" {");
$o->tabIn();
foreach my $pp (@{$this->{'pairs'}}) {
$pp->asS2($o);
}
$o->tabOut();
$o->writeln("}");
} else {
$o->writeln(";");
}
}
sub getName {
my $this = shift;
$this->{'uhName'} || $this->{'nt'}->getName();
}
sub asPerl {
my ($this, $bp, $o) = @_;
if ($this->{'use'}) {
$o->tabwriteln("register_property_use(" .
$bp->getLayerIDString() . "," .
$bp->quoteString($this->{'uhName'}) . ");");
return;
}
if ($this->{'hide'}) {
$o->tabwriteln("register_property_hide(" .
$bp->getLayerIDString() . "," .
$bp->quoteString($this->{'uhName'}) . ");");
return;
}
$o->tabwriteln("register_property(" .
$bp->getLayerIDString() . "," .
$bp->quoteString($this->{'nt'}->getName()) . ",{");
$o->tabIn();
$o->tabwriteln("\"type\"=>" . $bp->quoteString($this->{'nt'}->getType->toString) . ",");
foreach my $pp (@{$this->{'pairs'}}) {
$o->tabwriteln($bp->quoteString($pp->getKey()) . "=>" .
$bp->quoteString($pp->getVal()) . ",");
}
$o->tabOut();
$o->writeln("});");
}