Parent Directory
|
Revision Log
Revision 2622 - (view) (download) (as text)
| 1 : | sh002i | 2558 | package Value; |
| 2 : | my $pkg = 'Value'; | ||
| 3 : | dpvc | 2579 | use vars qw($context $defaultContext %Type); |
| 4 : | sh002i | 2558 | use strict; |
| 5 : | |||
| 6 : | dpvc | 2579 | ############################################################# |
| 7 : | sh002i | 2558 | # |
| 8 : | dpvc | 2579 | # Initialize the context |
| 9 : | # | ||
| 10 : | sh002i | 2558 | |
| 11 : | dpvc | 2579 | use Value::Context; |
| 12 : | |||
| 13 : | $defaultContext = Value::Context->new( | ||
| 14 : | lists => { | ||
| 15 : | 'Point' => {open => '(', close => ')'}, | ||
| 16 : | 'Vector' => {open => '<', close => '>'}, | ||
| 17 : | 'Matrix' => {open => '[', close => ']'}, | ||
| 18 : | 'List' => {open => '(', close => ')'}, | ||
| 19 : | }, | ||
| 20 : | flags => { | ||
| 21 : | # | ||
| 22 : | # For vectors: | ||
| 23 : | # | ||
| 24 : | ijk => 0, # print vectors as <...> | ||
| 25 : | # | ||
| 26 : | # For fuzzy reals: | ||
| 27 : | # | ||
| 28 : | useFuzzyReals => 1, | ||
| 29 : | tolerance => 1E-6, | ||
| 30 : | tolType => 'relative', | ||
| 31 : | zeroLevel => 1E-14, | ||
| 32 : | zeroLevelTol => 1E-12, | ||
| 33 : | dpvc | 2596 | # |
| 34 : | # word to use for infinity | ||
| 35 : | # | ||
| 36 : | infiniteWord => 'infinity', | ||
| 37 : | dpvc | 2622 | # |
| 38 : | # For functions | ||
| 39 : | # | ||
| 40 : | limits => [-2,2], | ||
| 41 : | num_points => 5, | ||
| 42 : | dpvc | 2579 | }, |
| 43 : | ); | ||
| 44 : | |||
| 45 : | $context = \$defaultContext; | ||
| 46 : | |||
| 47 : | |||
| 48 : | sh002i | 2558 | # |
| 49 : | # Precedence of the various types | ||
| 50 : | # (They will be promoted upward automatically when needed) | ||
| 51 : | # | ||
| 52 : | dpvc | 2579 | $$context->{precedence} = { |
| 53 : | dpvc | 2603 | 'Number' => 0, |
| 54 : | 'Real' => 1, | ||
| 55 : | 'Infinity' => 2, | ||
| 56 : | 'Complex' => 3, | ||
| 57 : | 'Point' => 4, | ||
| 58 : | 'Vector' => 5, | ||
| 59 : | 'Matrix' => 6, | ||
| 60 : | 'List' => 7, | ||
| 61 : | 'Interval' => 8, | ||
| 62 : | 'Union' => 9, | ||
| 63 : | dpvc | 2609 | 'String' => 10, |
| 64 : | 'Formula' => 11, | ||
| 65 : | dpvc | 2579 | }; |
| 66 : | sh002i | 2558 | |
| 67 : | # | ||
| 68 : | # Binding of perl operator to class method | ||
| 69 : | # | ||
| 70 : | dpvc | 2579 | $$context->{method} = { |
| 71 : | sh002i | 2558 | '+' => 'add', |
| 72 : | '-' => 'sub', | ||
| 73 : | '*' => 'mult', | ||
| 74 : | '/' => 'div', | ||
| 75 : | '**' => 'power', | ||
| 76 : | '.' => '_dot', # see _dot below | ||
| 77 : | 'x' => 'cross', | ||
| 78 : | '<=>' => 'compare', | ||
| 79 : | dpvc | 2579 | }; |
| 80 : | sh002i | 2558 | |
| 81 : | dpvc | 2601 | $$context->{pattern}{infinite} = '[-+]?inf(?:inity)?'; |
| 82 : | $$context->{pattern}{infinity} = '\+?inf(?:inity)?'; | ||
| 83 : | $$context->{pattern}{-infinity} = '-inf(?:inity)?'; | ||
| 84 : | dpvc | 2596 | |
| 85 : | dpvc | 2579 | push(@{$$context->{data}{values}},'method','precedence'); |
| 86 : | sh002i | 2558 | |
| 87 : | dpvc | 2579 | ############################################################# |
| 88 : | |||
| 89 : | sh002i | 2558 | # |
| 90 : | # Check if a value is a number, complex, etc. | ||
| 91 : | # | ||
| 92 : | dpvc | 2603 | sub matchNumber {my $n = shift; $n =~ m/^$$context->{pattern}{signedNumber}$/i} |
| 93 : | sub matchInfinite {my $n = shift; $n =~ m/^$$context->{pattern}{infinite}$/i} | ||
| 94 : | dpvc | 2579 | sub isReal {class(shift) eq 'Real'} |
| 95 : | sub isComplex {class(shift) eq 'Complex'} | ||
| 96 : | sub isFormula {class(shift) eq 'Formula'} | ||
| 97 : | dpvc | 2621 | sub isValue {my $v = shift; return (ref($v) || $v) =~ m/^Value::/} |
| 98 : | sh002i | 2558 | |
| 99 : | sub isNumber { | ||
| 100 : | my $n = shift; | ||
| 101 : | dpvc | 2579 | return $n->{tree}->isNumber if isFormula($n); |
| 102 : | return isReal($n) || isComplex($n) || matchNumber($n); | ||
| 103 : | sh002i | 2558 | } |
| 104 : | |||
| 105 : | sub isRealNumber { | ||
| 106 : | my $n = shift; | ||
| 107 : | dpvc | 2579 | return $n->{tree}->isRealNumber if isFormula($n); |
| 108 : | return isReal($n) || matchNumber($n); | ||
| 109 : | sh002i | 2558 | } |
| 110 : | |||
| 111 : | # | ||
| 112 : | dpvc | 2603 | # Convert non-Value objects to Values, if possible |
| 113 : | # | ||
| 114 : | sub makeValue { | ||
| 115 : | my $x = shift; | ||
| 116 : | return $x if ref($x); | ||
| 117 : | return Value::Real->make($x) if matchNumber($x); | ||
| 118 : | dpvc | 2609 | if (matchInfinite($x)) { |
| 119 : | my $I = Value::Infinity->new(); | ||
| 120 : | $I = $I->neg if $x =~ m/^$$Value::context->{pattern}{-infinity}$/; | ||
| 121 : | return $I; | ||
| 122 : | } | ||
| 123 : | if ($Parser::installed) {return $x unless $$Value::context->{strings}{$x}} | ||
| 124 : | return Value::String->make($x); | ||
| 125 : | dpvc | 2603 | } |
| 126 : | |||
| 127 : | # | ||
| 128 : | sh002i | 2558 | # Get a printable version of the class of an object |
| 129 : | # | ||
| 130 : | sub showClass { | ||
| 131 : | dpvc | 2621 | my $value = makeValue(shift); my $showFormula = shift; |
| 132 : | return "'".$value."'" unless Value::isValue($value); | ||
| 133 : | sh002i | 2558 | my $class = class($value); |
| 134 : | dpvc | 2621 | return showType($value) if ($class eq 'List'); |
| 135 : | dpvc | 2592 | $class .= ' Number' if $class =~ m/^(Real|Complex)$/; |
| 136 : | $class .= ' of Intervals' if $class eq 'Union'; | ||
| 137 : | dpvc | 2609 | $class = 'Word' if $class eq 'String'; |
| 138 : | dpvc | 2621 | return ($showFormula ? 'a Formula that returns ' : '') . showType($value->{tree}) |
| 139 : | if ($class eq 'Formula'); | ||
| 140 : | dpvc | 2603 | return 'an '.$class if $class =~ m/^[aeio]/i; |
| 141 : | sh002i | 2558 | return 'a '.$class; |
| 142 : | } | ||
| 143 : | |||
| 144 : | # | ||
| 145 : | # Get a printable version of the type of an object | ||
| 146 : | # | ||
| 147 : | sub showType { | ||
| 148 : | my $value = shift; | ||
| 149 : | my $type = $value->type; | ||
| 150 : | dpvc | 2621 | if ($type eq 'List') { |
| 151 : | my $ltype = $value->typeRef->{entryType}{name}; | ||
| 152 : | if ($ltype && $ltype ne 'unknown') { | ||
| 153 : | $ltype =~ s/y$/ie/; | ||
| 154 : | $type .= ' of '.$ltype.'s'; | ||
| 155 : | } | ||
| 156 : | } | ||
| 157 : | dpvc | 2609 | return 'a Word' if $type eq 'String'; |
| 158 : | sh002i | 2558 | return 'a Complex Number' if $value->isComplex; |
| 159 : | dpvc | 2603 | return 'an '.$type if $type =~ m/^[aeio]/i; |
| 160 : | sh002i | 2558 | return 'a '.$type; |
| 161 : | } | ||
| 162 : | |||
| 163 : | # | ||
| 164 : | dpvc | 2603 | # Return a string describing a value's type |
| 165 : | sh002i | 2558 | # |
| 166 : | sub getType { | ||
| 167 : | my $equation = shift; my $value = shift; | ||
| 168 : | my $strings = $equation->{context}{strings}; | ||
| 169 : | if (ref($value) eq 'ARRAY') { | ||
| 170 : | return 'Interval' if ($value->[0] =~ m/^[(\[]$/ && $value->[-1] =~ m/^[)\]]$/); | ||
| 171 : | my ($type,$ltype); | ||
| 172 : | foreach my $x (@{$value}) { | ||
| 173 : | $type = getType($equation,$x); | ||
| 174 : | if ($type eq 'value') { | ||
| 175 : | $type = $x->type if $x->class eq 'Formula'; | ||
| 176 : | $type = 'Number' if $x->class eq 'Complex' || $type eq 'Complex'; | ||
| 177 : | } | ||
| 178 : | $ltype = $type if $ltype eq ''; | ||
| 179 : | return 'List' if $type ne $ltype; | ||
| 180 : | } | ||
| 181 : | return 'Point' if $ltype eq 'Number'; | ||
| 182 : | return 'Matrix' if $ltype =~ m/Point|Matrix/; | ||
| 183 : | return 'List'; | ||
| 184 : | } | ||
| 185 : | elsif (Value::isFormula($value)) {return 'Formula'} | ||
| 186 : | dpvc | 2605 | elsif (Value::class($value) eq 'Infinity') {return 'String'} |
| 187 : | dpvc | 2612 | elsif (Value::isReal($value)) {return 'Number'} |
| 188 : | sh002i | 2558 | elsif (Value::isValue($value)) {return 'value'} |
| 189 : | elsif (ref($value)) {return 'unknown'} | ||
| 190 : | elsif (defined($strings->{$value})) {return 'String'} | ||
| 191 : | elsif (Value::isNumber($value)) {return 'Number'} | ||
| 192 : | return 'unknown'; | ||
| 193 : | } | ||
| 194 : | |||
| 195 : | # | ||
| 196 : | # Get a string describing a value's type, | ||
| 197 : | # and convert the value to a Value object (if needed) | ||
| 198 : | # | ||
| 199 : | sub getValueType { | ||
| 200 : | my $equation = shift; my $value = shift; | ||
| 201 : | my $type = Value::getType($equation,$value); | ||
| 202 : | if ($type eq 'String') {$type = $Value::Type{string}} | ||
| 203 : | elsif ($type eq 'Number') {$type = $Value::Type{number}} | ||
| 204 : | elsif ($type eq 'value') {$type = $value->typeRef} | ||
| 205 : | elsif ($type =~ m/unknown|Formula/) { | ||
| 206 : | $equation->Error("Can't convert ".Value::showClass($value)." to a constant"); | ||
| 207 : | } else { | ||
| 208 : | $type = 'Value::'.$type, $value = $type->new(@{$value}) unless $type eq 'value'; | ||
| 209 : | $type = $value->typeRef; | ||
| 210 : | } | ||
| 211 : | return ($value,$type); | ||
| 212 : | } | ||
| 213 : | |||
| 214 : | # | ||
| 215 : | # Convert a list of values to a list of formulas (called by Parser::Value) | ||
| 216 : | # | ||
| 217 : | sub toFormula { | ||
| 218 : | my $formula = shift; | ||
| 219 : | my $processed = 0; | ||
| 220 : | my @f = (); my $vars = {}; | ||
| 221 : | foreach my $x (@_) { | ||
| 222 : | if (isFormula($x)) { | ||
| 223 : | $formula->{context} = $x->{context}, $processed = 1 unless $processed; | ||
| 224 : | $formula->{variables} = {%{$formula->{variables}},%{$x->{variables}}}; | ||
| 225 : | push(@f,$x->{tree}->copy($formula)); | ||
| 226 : | } else { | ||
| 227 : | push(@f,Parser::Value->new($formula,$x)); | ||
| 228 : | } | ||
| 229 : | } | ||
| 230 : | return (@f); | ||
| 231 : | } | ||
| 232 : | |||
| 233 : | # | ||
| 234 : | # Convert a list of values (and open and close parens) | ||
| 235 : | # to a formula whose type is the list type associated with | ||
| 236 : | # the parens. If the formula is constant, evaluate it. | ||
| 237 : | # | ||
| 238 : | sub formula { | ||
| 239 : | my $self = shift; my $values = shift; | ||
| 240 : | my $class = $self->class; | ||
| 241 : | dpvc | 2579 | my $list = $$context->lists->get($class); |
| 242 : | my $open = $list->{'open'}; | ||
| 243 : | my $close = $list->{'close'}; | ||
| 244 : | sh002i | 2558 | my $formula = Value::Formula->blank; |
| 245 : | my @coords = Value::toFormula($formula,@{$values}); | ||
| 246 : | $formula->{tree} = Parser::List->new($formula,[@coords],0, | ||
| 247 : | $formula->{context}{parens}{$open},$coords[0]->typeRef,$open,$close); | ||
| 248 : | dpvc | 2579 | # return $formula->eval if scalar(%{$formula->{variables}}) == 0; |
| 249 : | sh002i | 2558 | return $formula; |
| 250 : | } | ||
| 251 : | |||
| 252 : | # | ||
| 253 : | # A shortcut for new() that creates an instance of the object, | ||
| 254 : | # but doesn't do the error checking. We assume the data are already | ||
| 255 : | # known to be good. | ||
| 256 : | # | ||
| 257 : | sub make { | ||
| 258 : | my $self = shift; my $class = ref($self) || $self; | ||
| 259 : | bless {data => [@_]}, $class; | ||
| 260 : | } | ||
| 261 : | |||
| 262 : | # | ||
| 263 : | # Return a type structure for the item | ||
| 264 : | # (includes name, length of vectors, and so on) | ||
| 265 : | # | ||
| 266 : | sub Type { | ||
| 267 : | my $name = shift; my $length = shift; my $entryType = shift; | ||
| 268 : | $length = 1 unless defined $length; | ||
| 269 : | return {name => $name, length => $length, entryType => $entryType, | ||
| 270 : | list => (defined $entryType), @_}; | ||
| 271 : | } | ||
| 272 : | |||
| 273 : | # | ||
| 274 : | # Some predefined types | ||
| 275 : | # | ||
| 276 : | %Type = ( | ||
| 277 : | number => Value::Type('Number',1), | ||
| 278 : | complex => Value::Type('Number',2), | ||
| 279 : | string => Value::Type('String',1), | ||
| 280 : | unknown => Value::Type('unknown',0,undef,list => 1) | ||
| 281 : | ); | ||
| 282 : | |||
| 283 : | # | ||
| 284 : | # Return various information about the object | ||
| 285 : | # | ||
| 286 : | sub value {return @{(shift)->{data}}} # the value of the object (as an array) | ||
| 287 : | sub data {return (shift)->{data}} # the reference to the value | ||
| 288 : | sub length {return (shift)->typeRef->{length}} # the number of coordinates | ||
| 289 : | sub type {return (shift)->typeRef->{name}} # the object type | ||
| 290 : | sub entryType {return (shift)->typeRef->{entryType}} # the coordinate type | ||
| 291 : | # | ||
| 292 : | # The the full type-hash for the item | ||
| 293 : | # | ||
| 294 : | sub typeRef { | ||
| 295 : | my $self = shift; | ||
| 296 : | return Value::Type($self->class, $self->length, $Value::Type{number}); | ||
| 297 : | } | ||
| 298 : | # | ||
| 299 : | # The Value.pm object class | ||
| 300 : | # | ||
| 301 : | sub class { | ||
| 302 : | my $self = shift; my $class = ref($self) || $self; | ||
| 303 : | $class =~ s/Value:://; | ||
| 304 : | return $class; | ||
| 305 : | } | ||
| 306 : | |||
| 307 : | # | ||
| 308 : | # Get an element from a point, vector, matrix, or list | ||
| 309 : | # | ||
| 310 : | sub extract { | ||
| 311 : | my $M = shift; my $i; | ||
| 312 : | while (scalar(@_) > 0) { | ||
| 313 : | return unless Value::isValue($M); | ||
| 314 : | $i = shift; $i-- if $i > 0; | ||
| 315 : | Value::Error("Can't extract element number '$i' (index must be an integer)") | ||
| 316 : | unless $i =~ m/^-?\d+$/; | ||
| 317 : | $M = $M->data->[$i]; | ||
| 318 : | } | ||
| 319 : | return $M; | ||
| 320 : | } | ||
| 321 : | |||
| 322 : | |||
| 323 : | # | ||
| 324 : | # Promote an operand to the same precedence as the current object | ||
| 325 : | # | ||
| 326 : | sub promotePrecedence { | ||
| 327 : | my $self = shift; my $other = shift; | ||
| 328 : | dpvc | 2579 | my $sprec = $$context->{precedence}{class($self)}; |
| 329 : | my $oprec = $$context->{precedence}{class($other)}; | ||
| 330 : | sh002i | 2558 | return defined($oprec) && $sprec < $oprec; |
| 331 : | } | ||
| 332 : | |||
| 333 : | dpvc | 2592 | sub promote {shift} |
| 334 : | |||
| 335 : | sh002i | 2558 | # |
| 336 : | # Default stub to call when no function is defined for an operation | ||
| 337 : | # | ||
| 338 : | sub nomethod { | ||
| 339 : | my ($l,$r,$flag,$op) = @_; | ||
| 340 : | dpvc | 2579 | my $call = $$context->{method}{$op}; |
| 341 : | sh002i | 2558 | if (defined($call) && $l->promotePrecedence($r)) {return $r->$call($l,!$flag)} |
| 342 : | my $error = "Can't use '$op' with ".$l->class."-valued operands"; | ||
| 343 : | $error .= " (use '**' for exponentiation)" if $op eq '^'; | ||
| 344 : | Value::Error($error); | ||
| 345 : | } | ||
| 346 : | |||
| 347 : | # | ||
| 348 : | # Stubs for the sub-classes | ||
| 349 : | # | ||
| 350 : | sub add {nomethod(@_,'+')} | ||
| 351 : | sub sub {nomethod(@_,'-')} | ||
| 352 : | sub mult {nomethod(@_,'*')} | ||
| 353 : | sub div {nomethod(@_,'/')} | ||
| 354 : | sub power {nomethod(@_,'**')} | ||
| 355 : | sub cross {nomethod(@_,'x')} | ||
| 356 : | |||
| 357 : | # | ||
| 358 : | # If the right operand is higher precedence, we switch the order. | ||
| 359 : | # | ||
| 360 : | # If the right operand is also a Value object, we do the object's | ||
| 361 : | # dot method to combine the two objects of the same class. | ||
| 362 : | # | ||
| 363 : | # Otherwise, since . is used for string concatenation, we want to retain | ||
| 364 : | # that. Since the resulting string is often used in Formula and will be | ||
| 365 : | dpvc | 2579 | # parsed again, we put parentheses around the values to guarantee that |
| 366 : | sh002i | 2558 | # the values will be treated as one mathematical unit. For example, if |
| 367 : | # $f = Formula("1+x") and $g = Formula("y") then Formula("$f/$g") will be | ||
| 368 : | # (1+x)/y not 1+(x/y), as it would be without the implicit parentheses. | ||
| 369 : | # | ||
| 370 : | sub _dot { | ||
| 371 : | my ($l,$r,$flag) = @_; | ||
| 372 : | return Value::_dot($r,$l,!$flag) if ($l->promotePrecedence($r)); | ||
| 373 : | return $l->dot($r,$flag) if (Value::isValue($r)); | ||
| 374 : | dpvc | 2606 | $l = $l->stringify; $l = '('.$l.')' unless $$Value::context->flag('StringifyAsTeX'); |
| 375 : | sh002i | 2558 | return ($flag)? ($r.$l): ($l.$r); |
| 376 : | } | ||
| 377 : | # | ||
| 378 : | # Some classes override this | ||
| 379 : | # | ||
| 380 : | dpvc | 2603 | sub dot { |
| 381 : | sh002i | 2558 | my ($l,$r,$flag) = @_; |
| 382 : | dpvc | 2606 | my $tex = $$Value::context->flag('StringifyAsTeX'); |
| 383 : | $l = $l->stringify; $l = '('.$l.')' if $tex; | ||
| 384 : | if (ref($r)) {$r = $r->stringify; $r = '('.$l.')' if $tex} | ||
| 385 : | sh002i | 2558 | return ($flag)? ($r.$l): ($l.$r); |
| 386 : | } | ||
| 387 : | |||
| 388 : | # | ||
| 389 : | # Compare the values of the objects | ||
| 390 : | # (list classes should replace this) | ||
| 391 : | # | ||
| 392 : | sub compare { | ||
| 393 : | my ($l,$r,$flag) = @_; | ||
| 394 : | if ($l->promotePrecedence($r)) {return $r->compare($l,!$flag)} | ||
| 395 : | return $l->value <=> $r->value; | ||
| 396 : | } | ||
| 397 : | |||
| 398 : | # | ||
| 399 : | # Generate the various output formats | ||
| 400 : | dpvc | 2606 | # (can be replaced by sub-classes) |
| 401 : | sh002i | 2558 | # |
| 402 : | dpvc | 2606 | sub stringify { |
| 403 : | my $self = shift; | ||
| 404 : | return $self->TeX() if $$Value::context->flag('StringifyAsTeX'); | ||
| 405 : | dpvc | 2612 | $self->string; |
| 406 : | dpvc | 2606 | } |
| 407 : | sub string {shift->value} | ||
| 408 : | sub TeX {shift->string(@_)} | ||
| 409 : | sh002i | 2558 | # |
| 410 : | # For perl, call the appropriate constructor around the objects data | ||
| 411 : | # | ||
| 412 : | sub perl { | ||
| 413 : | my $self = shift; my $parens = shift; my $matrix = shift; | ||
| 414 : | my $class = $self->class; my $mtype = $class eq 'Matrix'; | ||
| 415 : | my $perl; my @p = (); | ||
| 416 : | foreach my $x (@{$self->data}) { | ||
| 417 : | if (Value::isValue($x)) {push(@p,$x->perl(0,$mtype))} else {push(@p,$x)} | ||
| 418 : | } | ||
| 419 : | @p = ("'".$self->{open}."'",@p,"'".$self->{close}."'") if $class eq 'Interval'; | ||
| 420 : | if ($matrix) { | ||
| 421 : | $perl = '['.join(',',@p).']'; | ||
| 422 : | } else { | ||
| 423 : | $perl = $class.'('.join(',',@p).')'; | ||
| 424 : | $perl = '('.$perl.')' if $parens == 1; | ||
| 425 : | } | ||
| 426 : | return $perl; | ||
| 427 : | } | ||
| 428 : | |||
| 429 : | # | ||
| 430 : | # Stubs for when called by Parser | ||
| 431 : | # | ||
| 432 : | sub eval {shift} | ||
| 433 : | sub reduce {shift} | ||
| 434 : | |||
| 435 : | dpvc | 2579 | sub ijk { |
| 436 : | Value::Error("Can't use method 'ijk' with objects of type '".(shift)->class."'"); | ||
| 437 : | } | ||
| 438 : | |||
| 439 : | sh002i | 2558 | # |
| 440 : | # Report an error | ||
| 441 : | # | ||
| 442 : | sub Error { | ||
| 443 : | my $message = shift; | ||
| 444 : | dpvc | 2579 | $$context->setError($message,''); |
| 445 : | dpvc | 2592 | # die $message . traceback(); |
| 446 : | die $message . getCaller(); | ||
| 447 : | sh002i | 2558 | } |
| 448 : | |||
| 449 : | # | ||
| 450 : | # Try to locate the line and file where the error occurred | ||
| 451 : | # | ||
| 452 : | sub getCaller { | ||
| 453 : | my $frame = 2; | ||
| 454 : | while (my ($pkg,$file,$line,$subname) = caller($frame++)) { | ||
| 455 : | return " at line $line of $file\n" | ||
| 456 : | unless $pkg =~ /^(Value|Parser)/ || | ||
| 457 : | $subname =~ m/^(Value|Parser).*(new|call)$/; | ||
| 458 : | } | ||
| 459 : | return ""; | ||
| 460 : | } | ||
| 461 : | |||
| 462 : | dpvc | 2579 | # |
| 463 : | # For debugging | ||
| 464 : | # | ||
| 465 : | sub traceback { | ||
| 466 : | my $frame = 2; | ||
| 467 : | my $trace = ''; | ||
| 468 : | while (my ($pkg,$file,$line,$subname) = caller($frame++)) | ||
| 469 : | {$trace .= " in $subname at line $line of $file\n"} | ||
| 470 : | return $trace; | ||
| 471 : | } | ||
| 472 : | |||
| 473 : | sh002i | 2558 | ########################################################################### |
| 474 : | # | ||
| 475 : | # Load the sub-classes. | ||
| 476 : | # | ||
| 477 : | |||
| 478 : | dpvc | 2579 | use Value::Real; |
| 479 : | sh002i | 2558 | use Value::Complex; |
| 480 : | dpvc | 2603 | use Value::Infinity; |
| 481 : | sh002i | 2558 | use Value::Point; |
| 482 : | use Value::Vector; | ||
| 483 : | use Value::Matrix; | ||
| 484 : | use Value::List; | ||
| 485 : | use Value::Interval; | ||
| 486 : | use Value::Union; | ||
| 487 : | dpvc | 2609 | use Value::String; |
| 488 : | sh002i | 2558 | # use Value::Formula; |
| 489 : | |||
| 490 : | dpvc | 2592 | use Value::AnswerChecker; # for WeBWorK |
| 491 : | |||
| 492 : | sh002i | 2558 | ########################################################################### |
| 493 : | dpvc | 2592 | |
| 494 : | use vars qw($installed); | ||
| 495 : | $Value::installed = 1; | ||
| 496 : | |||
| 497 : | ########################################################################### | ||
| 498 : | ########################################################################### | ||
| 499 : | dpvc | 2576 | # |
| 500 : | # To Do: | ||
| 501 : | # | ||
| 502 : | dpvc | 2579 | # Make Complex class include more of Complex1.pm |
| 503 : | # Make better interval comparison | ||
| 504 : | dpvc | 2576 | # |
| 505 : | ########################################################################### | ||
| 506 : | sh002i | 2558 | |
| 507 : | dpvc | 2592 | 1; |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |