@@ -57,7 +57,7 @@ use parent qw(Exporter);
5757use strict;
5858use warnings;
5959
60- our @EXPORT = qw( convertToPGML) ;
60+ our @EXPORT_OK = qw( convertToPGML) ;
6161
6262=head2 convertToPGML
6363
@@ -76,16 +76,6 @@ my @ans_list;
7676sub convertToPGML {
7777 my ($pg_source ) = @_ ;
7878
79- # Check that the file is not already in PGML format by looking for PGML.pl in the loadMacros statement,
80- # and there are no BEGIN_TEXT, BEGIN_SOLUTION, etc. blocks.
81-
82- return { pgmlCode => $pg_source }
83- if ($pg_source =~ / loadMacros\( (.*)PGML\. pl(.*)\) /m && $pg_source !~ / BEGIN_(TEXT|HINT|SOLUTION)/ );
84-
85- # Return an error if the loadMacros isn't in the form loadMacros( ... );
86- return { errors => " The loadMacros command cannot be parsed." , pgmlCode => $pg_source }
87- unless $pg_source =~ / loadMacros\( (.*?)\)\s *;/m ;
88-
8979 # Get a list of all of the ANS, LABELED_ANS, etc. in the problem.
9080 @ans_list = getANS($pg_source );
9181
@@ -123,58 +113,32 @@ sub convertToPGML {
123113 }
124114 $macros .= $row ;
125115
126- my @macros ;
127- my ($qw_start , $qw_end ); # the characters if the loadMacros has a qw block.
128-
129- # The following can parse loadMacros in the form loadMacros('macro1.pl', 'macro2.pl'); or
130- # loadMacros(qw{macro1.pl macro2.pl});
131- if ($macros =~ / loadMacros\( (.*?)\) ;/ms ) {
132- my @macro_str = split (/ \s *,\s */ , $1 );
133-
134- for my $str (@macro_str ) {
135- if ($str =~ / ^qw(.)/ ) {
136- my $qw_matches = { ' {' => ' }' , ' (' => ' )' , ' [' => ' ]' , ' /' => ' /' , ' |' => ' |' };
137- $qw_start = $1 ;
138- $qw_end = $qw_matches -> {$qw_start };
139-
140- if ($str =~ / ^qw\Q ${qw_start} \E (.*?)\Q ${qw_end} \E / ) {
141- push (@macros , split (/ \s +/ , $1 ));
142- }
143- } else {
144- push (@macros , $str );
145- }
146- }
116+ my $load_macros_block = parseLoadMacros($macros );
147117
148- @macros =
149- grep {
150- $_
151- && $_ !~
152- / (PGstandard|PGML|PGauxiliaryFunctions|PGbasicmacros|PGanswermacros|MathObjects|PGcourse|AnswerFormatHelp).pl/x
153- }
154- map {s / ['"]// gr } @macros ;
155-
156- # Remove any duplicates:
157- my %seen ;
158- @macros = grep { !$seen {$_ }++ } @macros ;
159- } else {
160- return {
161- errors => ' The loadMacros command cannot be processed.' ,
162- pgmlCode => $pg_source
163- };
164- }
118+ # If PGML.pl is a macro and there are no BEGIN_TEXT/HINT/SOLUTION blocks
119+ # return the original source.
120+ return { pgmlCode => $pg_source }
121+ if (!defined ($load_macros_block -> {errors })
122+ && grep { $_ eq ' PGML.pl' } @{ $load_macros_block -> {macros } }
123+ && $pg_source !~ / ^\s *BEGIN_(TEXT|HINT|SOLUTION)/m );
165124
166- @macros = ( ' PGstandard.pl ' , ' PGML.pl ' , @macros , ' PGcourse.pl ' );
125+ return { errors => $load_macros_block -> { errors }, pgmlCode => $pg_source } if ( $load_macros_block -> { errors } );
167126
168- if ($qw_start ) {
127+ if ($load_macros_block -> { qw_start } ) {
169128 if ($num_macro_lines > 1) { # put each macro on a separate line
170- push (@all_lines , " loadMacros(qw$ qw_start" );
171- push (@all_lines , " \t $_ " ) for (@macros );
172- push (@all_lines , " $ qw_end); " );
129+ push (@all_lines , ' loadMacros(qw' . $load_macros_block -> { qw_start } );
130+ push (@all_lines , " \t $_ " ) for (@{ $load_macros_block -> { macros } } );
131+ push (@all_lines , $load_macros_block -> { qw_end } . ' ); ' );
173132 } else {
174- push (@all_lines , " loadMacros(qw$qw_start " . join (' ' , @macros ) . " $qw_end );" , ' ' );
133+ push (@all_lines ,
134+ ' loadMacros(qw'
135+ . $load_macros_block -> {qw_start }
136+ . join (' ' , @{ $load_macros_block -> {macros } })
137+ . $load_macros_block -> {qw_end } . ' );' ,
138+ ' ' );
175139 }
176140 } else {
177- push (@all_lines , ' loadMacros(' . join (' , ' , map {" '$_ '" } @macros ) . ' );' , ' ' );
141+ push (@all_lines , ' loadMacros(' . join (' , ' , map {" '$_ '" } @{ $load_macros_block -> { macros } } ) . ' );' , ' ' );
178142 }
179143 } else {
180144 push (@all_lines , cleanUpCode($row ));
@@ -192,6 +156,56 @@ sub convertToPGML {
192156 return { pgmlCode => join " \n " , @all_lines };
193157}
194158
159+ sub parseLoadMacros {
160+ my ($macros ) = @_ ;
161+
162+ my $error_string = ' The loadMacros statement could not be parsed. Check for syntax errors.' ;
163+
164+ return { errors => $error_string }
165+ if $macros =~ / loadMacros\( .*?\) (.*?);/s && $1 !~ / ^\s *$ /m ;
166+
167+ my @macros ;
168+ my ($qw_start , $qw_end ); # the characters if the loadMacros has a qw block.
169+ my $qw_matches = { ' {' => ' }' , ' (' => ' )' , ' [' => ' ]' , ' /' => ' /' , ' |' => ' |' };
170+
171+ # The following can parse loadMacros in the form loadMacros('macro1.pl', 'macro2.pl'); or
172+ # loadMacros(qw{macro1.pl macro2.pl});
173+ if ($macros =~ / loadMacros\( (.*?)\) ;/ms ) {
174+ my @macro_str = split (/ \s *,\s */ , $1 );
175+
176+ for my $str (@macro_str ) {
177+ if ($str =~ / ^qw(.)/ ) {
178+ $qw_start = $1 ;
179+ $qw_end = $qw_matches -> {$qw_start };
180+ push (@macros , split (/ \s +/ , $1 )) if $str =~ / ^qw\Q ${qw_start} \E (.*?)\Q ${qw_end} \E / ;
181+ } else {
182+ push (@macros , $str );
183+ }
184+ }
185+
186+ @macros =
187+ grep {
188+ $_
189+ && $_ !~
190+ / (PGstandard|PGML|PGauxiliaryFunctions|PGbasicmacros|PGanswermacros|MathObjects|PGcourse|AnswerFormatHelp).pl/x
191+ }
192+ map {s / ['"]// gr } @macros ;
193+
194+ # Remove any duplicates:
195+ my %seen ;
196+ @macros = grep { !$seen {$_ }++ } @macros ;
197+ } else {
198+ return { errors => $error_string };
199+ }
200+
201+ @macros = (' PGstandard.pl' , ' PGML.pl' , @macros , ' PGcourse.pl' );
202+ return {
203+ qw_start => $qw_start ,
204+ qw_end => $qw_end ,
205+ macros => \@macros
206+ };
207+ }
208+
195209# This subroutine converts a block (passed in as an array ref of strings) to
196210# PGML format. This includes:
197211# * converting BEGIN_TEXT/END_TEXT to BEGIN_PGML/END_PGML
@@ -266,12 +280,12 @@ sub convertPGMLBlock {
266280 }
267281
268282 # After many other variables have been replaced, replace the variables in the PGML block.
269- # However if not in a {}, assumed to be in an answer blank .
283+ # If a variable is inside [_] {}, like '[_]{$a}', then leave it alone .
270284 if (my @matches = $row =~ / \$ [\w\_ ]+/g ) {
271- for my $m ( @matches ) {
272- $m =~ s / \$ / \\\$ / ;
273- # Wrap variables in []. Handle arrays, hashes, array refs and hashrefs.
274- $row =~ s /(?<! \] {)($m+( \[\d + \] )?((->)? \{ .*? \} )?) / [$1 ]/ ;
285+ my %seen ;
286+ for my $m ( grep { ! $seen { $_ }++ } @matches ) {
287+ # $row =~ s/(?<!\{)(\Q$m\E)(?!\})/[$1]/g;
288+ $row =~ s /\[ _+ \]\{\Q $m \E\} (*SKIP)(*F)|( \Q $m \E ) / [$1 ]/ g ;
275289 }
276290 }
277291
0 commit comments