########################################################################## ## All portions of this code are copyright (c) 2003,2004 nethype GmbH ## ########################################################################## ## Using, reading, modifying or copying this code requires a LICENSE ## ## from nethype GmbH, Franz-Werfel-Str. 11, 74078 Heilbronn, ## ## Germany. If you happen to have questions, feel free to contact us at ## ## license@nethype.de. ## ########################################################################## =head1 NAME PApp::Parser - PApp format file parser =head1 SYNOPSIS =head1 DESCRIPTION This module manages F<.papp> files (parsing, compiling etc..). You have to look at the examples to understand the descriptions here :( This module exports nothing (and might never do). =over 4 =cut package PApp::Parser; use Carp; use Convert::Scalar ':utf8'; use PApp::Exception; use PApp::SQL; use PApp::Util; use PApp::Config; use PApp::PCode qw(pxml2pcode xml2pcode perl2pcode pcode2pxml pcode2perl); use PApp::XML qw(xml2utf8); use PApp::I18n qw(normalize_langid); no bytes; use utf8; $VERSION = 1.43; =item ($ppkg, $name, $code) = parse_file $papp, $path Parse the specified file and return the tree of nested packages ($ppkg, the config data) and the tree containing all the (prepocessed) sourcecode that implements the semantics ($code). $name contains the name of the topmost (root) package. =cut sub parse_file { my $papp = shift; my $path = shift; my @curpmod; # current pmod stack my @curppkg; # current papp stack my @curend; my @curchr = (undef); my @curxsl; my @curfile; my @curwant; my @curdom = ['default','*']; my $parser; my $curcode; my @curpath; my @curnosession; my $root; my %code; my $code; my $lineinfo = sub { PApp::PCode::perl2pcode "\n;\n#line ".($_[0]->current_line)." \"$path\"\n"; }; my $load_fragment; my $handler = { Char => sub { my ($self, $cdata) = @_; if ($curwant[-1]) { $curchr[-1] .= $cdata; } elsif ($cdata !~ /^\s*$/) { $self->xpcroak("no character data allowed here"); } 1; }, End => sub { #my ($self, $element) = @_; (pop @curend)->(pop @curchr); pop @curwant; 1; }, Start => sub { my ($self, $element, %attr) = @_; my $end = sub { }; my $ppkg = $curppkg[-1]; my $pmod = $curpmod[-1]; push @curwant, 0; push @curchr, ""; if ($element eq "package") { length $attr{name} > 1 or $parser->xpcroak(": required attribute 'name' missing or empty"); if ($ppkg) { my $pkg = new PApp::Package; $ppkg->{pkg}{$attr{name}} = $pkg; $ppkg = $pkg; } else { $root and fancydie "$path must only contain a single \n"; $ppkg = $root = new PApp::Package; } $ppkg->{domain} = $curdom[-1][0]; $ppkg->{name} = $attr{name}; $ppkg->{surlstyle} = $attr{surlstyle} eq "get" ? scalar &PApp::SURL_STYLE_GET : scalar &PApp::SURL_STYLE_URL; push @curppkg, $ppkg; push @curpath, $attr{name}; push @curpmod, undef; $code = \%{$code{"/".join "/", @curpath}}; push @apps, $ppkg unless @curppkg; #FIXME# necessary?? #my $pmod = new PApp::Module; #FIXME# still needed? #$ppkg->{"/"} = $pmod; #push @curpmod, $pmod; push @curxsl, undef; # style tags don't propagate $end = sub { $code->{body} .= pcode2perl $_[0]; pop @curppkg; pop @curpmod; pop @curpath; pop @curxsl; $code = \%{$code{"/".join "/", @curpath}} if @curpath; #FIXME# better use a stack? }; if (defined $attr{src}) { # this is merely an include my $src = PApp::Util::find_file $attr{src}, ["papp"], URI->new_abs (".", $path); eval { $load_fragment->($src) }; $@ and fancydie "file '$attr{src}', included in line ".$self->current_line, $@; } } elsif ($element eq "domain") { @curppkg or $self->xpcroak("<$element> found outside any package (not yet supported)"); push @curdom, [$attr{name} || $ppkg->{name}, normalize_langid($attr{lang} || "*")]; $ppkg->{domain} = $curdom[-1][0]; push @{$ppkg->{langs}}, split /[ \t\n,]/, $curdom[-1][1]; $papp->{file}{$path}{domain} = $curdom[-1][0]; $papp->{file}{$path}{lang} = $curdom[-1][1]; $end = sub { $curchr[-1] .= $_[0]; pop @curdom; }; } elsif ($element eq "style") { $attr{src} or $attr{expr} or $self->xpcroak("