# Copyright (c) 1997-2007 # Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) # http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any # later version: http://www.gnu.org/licenses/gpl.txt. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. #---------------------------------------------------------------------------- # $Project: polymake $$Id: Shell.pm 7550 2007-01-10 12:25:54Z gawrilow $ use strict; use namespaces; use Poly::Application; use Poly::User; use Poly::File; use Poly::Object; use Poly::Pipe; package Poly::Shell; use Poly::Ext; ### FIXME: to be filled with interactive stuff sub new { bless [ ]; } sub run { die "interactive mode not implemented yet\n"; redefine Help("Poly::InteractiveHelp"); } # the following three routines should access customizable variables from Poly::User package sub load_apps { eval { package Poly::User; if ((my ($app_name)=@_)>0) { if (!defined($_[0]) || $_[0] eq "none") { $application=_new Application(shift); } else { application($app_name); } } else { foreach $app_name (@start_applications) { add Application($app_name); } application($default_application); } }; if ($@) { err_print($@); exit 1; } } sub run_script { my ($scriptfile)=@_; $scriptfile =~ s/^(\w+)::(?!$)//; load_apps($1); package Poly::User; local @INC=($application, @INC, new Poly::Shell::BadScriptHandler); local_unshift($application->myINC, ".", @lookup_scripts, $application->top."/scripts", "$main::InstallTop/scripts"); local_array($application->compile_preamble, [ "use strict; use namespaces;\n" ]); local *default::=get_pkg(__PACKAGE__); do $scriptfile; beautify_error() if $@; } sub eval_expr { package Poly::User; local_unshift(\@INC, $application); local_unshift($application->myINC, ".", @lookup_scripts, $application->top."/scripts", "$main::InstallTop/scripts"); local_array($application->compile_preamble, [ "use strict; use namespaces;\n" ]); eval shift; beautify_error() if $@; } # the line is considered as to be continued if it ends with: # - an opening bracket whatever kind: { ( [ # - a binary operator: + - * / . cmp eq ... # - a colon or a semicolon sub is_continued { $_[0] =~ m'(?: [{([.,;*/<>=] | (?)) { while (is_continued($cmd) && length($line=<$pipe>)) { $cmd.=$line; } if (!$apps_loaded) { if ($cmd !~ /^\s* application (?:\s+|\()['"]\w+/xs) { load_apps; } $apps_loaded=1; } local $main::scope=new Scope(); eval_expr($cmd); if ($@) { err_print($@); } else { $main::scope->perform_deferred; } } $@=''; } ############################################################################################### my @request; package Poly::Shell::Dummy; my $dummy=bless [ ]; sub AUTOLOAD { $dummy } package Poly::User::Prepare; sub AUTOLOAD { $AUTOLOAD =~ /([^:]+)$/; if (@_) { die "unknown method or property: $1\n"; } push @request, $1; $dummy; } sub the_rest { wantarray ? () : $dummy; } sub prepare { no strict 'refs'; while (my ($func, $attr)=each %{$application->EXPORT}) { *$func= is_code($attr) ? \&the_rest : $attr eq "prop" ? \&$func : \&the_rest; } @request=(); } ############################################################################################### package Poly::Shell; sub compat_mode { my $file=shift; if (-f $file) { # old style syntax: FILE PROPERTY ... Poly::User::load($file); if ($Switches::verify) { $Poly::User::this->verify(@_); return; } do { package Poly::User::Prepare; prepare(); my $i=1; foreach (@_) { if (/^ $id_only_re /ox and defined (my $label=$application->prefs->find_label($1))) { if ($i<=$#_) { if ($application->EXPORT->{$1} eq "user") { warn_print( <<"." ); $1 is interpreted as prefer_now "$1"; but this is probably not exactly the same as you have meant. The recommended way to enforce using $1 is to call it explicitly: $1($_[$i]) . } $label->set_temp_preferred($main::scope); } else { warn_print( <<"." ); $1 is a label controlling the choice of functions following it on the command line. Being put on the last position it does not affect anything. . } undef $_; } else { eval $_; if ($@) { $@ =~ s/^Bareword "([^"]+)" not allowed .*$/Unknown method, property, or label: $1/mg unless $Switches::d; die beautify_error(); } } ++$i; } }; if ($Switches::n) { if (defined (my $schedule=$Poly::User::this->give_schedule(@request))) { print $schedule->report, "\n"; } else { err_print( "no suitable rules found\n" ); } return; } $Poly::User::this->give(@request); foreach my $expr (@_) { next unless defined $expr; my @pr=do { package Poly::User; no strict 'vars'; eval "printable($expr)" }; die beautify_error() if $@; if (@pr) { enforce_nl($pr[-1]); print "$expr\n", @pr, "\n"; } } } elsif ($file =~ /^ $id_only_re/xo) { # slight variation of the old style: FUNCTION FILE ... my $files_seen=0; foreach my $arg (@_) { if (-f $arg) { $arg=Poly::User::load($arg); ++$files_seen; } } load_apps if !$files_seen; if (my $function=Poly::User->can($file)) { if ($Switches::n) { die "can't call function $file in dry run mode\n"; } if (my @pr=Poly::User::printable($function->(@_))) { enforce_nl($pr[-1]); print "$file\n", @pr, "\n"; } } else { die "unknown function or file name: $file\n"; } } else { die "file $file does not exist\n"; } } ############################################################################################### # make this function visible for all modules and applications sub Modules::returnObject { my $obj=shift; $obj->commit; # try to guess the destination user variable if (defined (my $name=return_to_var())) { $obj->name ||= $name; } defined(wantarray) ? $obj : ($Poly::User::this=$obj); } package Poly::Shell::BadScriptHandler; my $dummy=bless [ ]; sub new { $dummy; } sub Poly::Shell::BadScriptHandler::INC { $@="script file '" . pop(@_) . "' not found\n"; undef; } 1