[system] / trunk / pg / macros / contextLimitedVector.pl Repository: Repository Listing bbplugincoursesdistsnplrochestersystemwww

# View of /trunk/pg/macros/contextLimitedVector.pl

Revision 3371 - (download) (as text) (annotate)
Tue Jul 12 22:39:56 2005 UTC (14 years, 7 months ago) by dpvc
File size: 7837 byte(s)
```Make error messages potentially localizable (by making them use
sprintf-style strings rather than variable subtitution).
```

```    1 loadMacros("Parser.pl");
2
3 sub _contextLimitedVector_init {}; # don't load it again
4
5 ##########################################################
6 #
7 #  Implements a context in which vectors can be entered,
8 #  but no vector operations are permitted.  So students will
9 #  be able to perform operations within the coordinates
10 #  of the vectors, but not between vectors.
11 #
12 #  Vectors can still be entered either in < , , > or ijk format.
13 #  Most of the complication here is to handle ijk format
14 #  properly.  Each coordinate vector is allowed to appear
15 #  only once, so we have to keep track of that, and allow
16 #  SOME vector operations, but only when one term is
17 #  one of the coordinate constants, or one of the formulas
18 #  we've already OKed.
19 #
20 #  You control which format to use by setting the context
21 #  to one of the following:
22 #
23 # Context("LimitedVector-coordinate");
24 #       Context("LimitedVector-ijk");
25 #       Context("LimitedVector");      # either one
26 #
27
28 #
29 #  Handle common checking for BOPs
30 #
31 package LimitedVector::BOP;
32
33 #
34 #  Do original check and then if the operands are numbers, its OK.
35 #  Otherwise, check if there is a duplicate constant from either term
36 #  Otherwise, do an operator-specific check for if vectors are OK.
37 #  Otherwise report an error.
38 #
39 sub _check {
40   my \$self = shift;
41   my \$super = ref(\$self); \$super =~ s/LimitedVector/Parser/;
42   &{\$super."::_check"}(\$self);
43   return if \$self->checkNumbers;
44   if (\$self->{equation}{context}{flags}{vector_format} ne 'coordinate') {
45     \$self->checkConstants(\$self->{lop});
46     \$self->checkConstants(\$self->{rop});
47     return if \$self->checkVectors;
48   }
49   my \$bop = \$self->{def}{string} || \$self->{bop};
50   \$self->Error("In this context, '%s' can only be used with Numbers",\$bop)
51     if \$self->{equation}{context}{flags}{vector_format} eq 'coordinate';
52   \$self->Error("In this context, '%s' can only be used with Numbers or i,j and k",\$bop);
53 }
54
55 #
56 #  filled in by subclasses
57 #
58 sub checkVectors {return 0}
59
60 #
61 #  Check if a constant has been repeated
62 #  (we maintain a hash that lists if one is below us in the parse tree)
63 #
64 sub checkConstants {
65   my \$self = shift; my \$op = shift;
66   my \$duplicate = '';
67   if (\$op->class eq 'Constant') {
68     return unless \$op->{name} =~ m/^[ijk]\$/;
69     \$duplicate = \$op->{name} if \$self->{ijk}{\$op->{name}};
70     \$self->{ijk}{\$op->{name}} = 1;
71   } else {
72     foreach my \$x ('i','j','k') {
73       \$duplicate = \$x if \$self->{ijk}{\$x} && \$op->{ijk}{\$x};
74       \$self->{ijk}{\$x} = \$self->{ijk}{\$x} || \$op->{ijk}{\$x};
75     }
76   }
77   Value::Error("The constant '%s' may appear only once in your formula",\$duplicate)
78     if \$duplicate;
79 }
80
81 ##############################################
82 #
83 #  Now we get the individual replacements for the operators
84 #  that we don't want to allow.  We inherit everything from
85 #  the original Parser::BOP class, and just add the
86 #  vector checks here.
87 #
88
90 our @ISA = qw(LimitedVector::BOP Parser::BOP::add);
91
92 sub checkVectors {
93   my \$self = shift;
94   return ((\$self->{lop}->class eq 'Constant' || \$self->{lop}->class =~ m/[BU]OP/) &&
95           (\$self->{rop}->class eq 'Constant' || \$self->{rop}->class =~ m/[BU]OP/));
96 }
97
98 ##############################################
99
100 package LimitedVector::BOP::subtract;
101 our @ISA = qw(LimitedVector::BOP Parser::BOP::subtract);
102
103 sub checkVectors {
104   my \$self = shift;
105   return ((\$self->{lop}->class eq 'Constant' || \$self->{lop}->class =~ m/[BU]OP/) &&
106           (\$self->{rop}->class eq 'Constant' || \$self->{rop}->class =~ m/[BU]OP/));
107 }
108
109 ##############################################
110
111 package LimitedVector::BOP::multiply;
112 our @ISA = qw(LimitedVector::BOP Parser::BOP::multiply);
113
114 sub checkVectors {
115   my \$self = shift;
116   return ((\$self->{lop}->class eq 'Constant' || \$self->{lop}->type eq 'Number') &&
117     (\$self->{rop}->class eq 'Constant' || \$self->{rop}->type eq 'Number'));
118 }
119
120 ##############################################
121
122 package LimitedVector::BOP::divide;
123 our @ISA = qw(LimitedVector::BOP Parser::BOP::divide);
124
125 sub checkVectors {
126   my \$self = shift;
127   my \$bop = \$self->{def}{string} || \$self->{bop};
128   \$self->Error("In this context, '%s' can only be used with Numbers",\$bop);
129 }
130
131 ##############################################
132 ##############################################
133 #
134 #  Now we do the same for the unary operators
135 #
136
137 package LimitedVector::UOP;
138
139 sub _check {
140   my \$self = shift;
141   my \$super = ref(\$self); \$super =~ s/LimitedVector/Parser/;
142   &{\$super."::_check"}(\$self);
143   return if \$self->checkNumber;
144   if (\$self->{equation}{context}{flags}{vector_format} ne 'coordinate') {
145     LimitedVector::BOP::checkConstants(\$self,\$self->{op});
146     return if \$self->checkVector;
147   }
148   my \$uop = \$self->{def}{string} || \$self->{uop};
149   \$self->Error("In this context, '%s' can only be used with Numbers",\$uop)
150     if \$self->{equation}{context}{flags}{vector_format} eq 'coordinate';
151   \$self->Error("In this context, '%s' can only be used with Numbers or i,j and k",\$uop);
152 }
153
154 sub checkVector {return 0}
155
156 ##############################################
157
158 package LimitedVector::UOP::plus;
159 our @ISA = qw(LimitedVector::UOP Parser::UOP::plus);
160
161 sub checkVector {return shift->{op}->class eq 'Constant'}
162
163 ##############################################
164
165 package LimitedVector::UOP::minus;
166 our @ISA = qw(LimitedVector::UOP Parser::UOP::minus);
167
168 sub checkVector {return shift->{op}->class eq 'Constant'}
169
170 ##############################################
171 ##############################################
172 #
173 #  Absolute value does vector norm, so we
174 #  trap that as well.
175 #
176
177 package LimitedVector::List::AbsoluteValue;
178 our @ISA = qw(Parser::List::AbsoluteValue);
179
180 sub _check {
181   my \$self = shift;
182   \$self->SUPER::_check;
183   return if \$self->{coords}[0]->type eq 'Number';
184   \$self->Error("Vector norm is not allowed in this context");
185 }
186
187 ##############################################
188
189 package LimitedVector::List::Vector;
190 our @ISA = qw(Parser::List::Vector);
191
192 sub _check {
193   my \$self = shift;
194   \$self->SUPER::_check;
195   return if \$self->{equation}{context}{flags}{vector_format} ne 'ijk';
196   \$self->Error("Vectors must be given in the form 'ai+bj+ck' in this context");
197 }
198
199 ##############################################
200 ##############################################
201
202 package main;
203
204 #
205 #  Now build the new context that calls the
206 #  above classes rather than the usual ones
207 #
208
209 \$context{LimitedVector} = Context("Vector");
210 \$context{LimitedVector}->operators->set(
211    '+' => {class => 'LimitedVector::BOP::add'},
212    '-' => {class => 'LimitedVector::BOP::subtract'},
213    '*' => {class => 'LimitedVector::BOP::multiply'},
214   '* ' => {class => 'LimitedVector::BOP::multiply'},
215   ' *' => {class => 'LimitedVector::BOP::multiply'},
216    ' ' => {class => 'LimitedVector::BOP::multiply'},
217    '/' => {class => 'LimitedVector::BOP::divide'},
218   ' /' => {class => 'LimitedVector::BOP::divide'},
219   '/ ' => {class => 'LimitedVector::BOP::divide'},
220   'u+' => {class => 'LimitedVector::UOP::plus'},
221   'u-' => {class => 'LimitedVector::UOP::minus'},
222 );
223 #
224 #  Remove these operators and functions
225 #
226 \$context{LimitedVector}->operators->undefine('_','U','><','.');
227 \$context{LimitedVector}->functions->undefine('norm','unit');
228 \$context{LimitedVector}->lists->set(
229   AbsoluteValue => {class => 'LimitedVector::List::AbsoluteValue'},
230   Vector        => {class => 'LimitedVector::List::Vector'},
231 );
232 #
233 #  Format can be 'coordinate', 'ijk', or 'either'
234 #
235 \$context{LimitedVector}->flags->set(vector_format => 'either');
236
237 \$context{'LimitedVector-ijk'} = \$context{LimitedVector}->copy;
238 \$context{'LimitedVector-ijk'}->flags->set(vector_format => 'ijk');
239
240 \$context{'LimitedVector-coordinate'} = \$context{LimitedVector}->copy;
241 \$context{'LimitedVector-coordinate'}->flags->set(vector_format => 'coordinate');
242 \$context{'LimitedVector-coordinate'}->constants->undefine('i','j','k');
243
244 Context("LimitedVector");
```

 aubreyja at gmail dot com ViewVC Help Powered by ViewVC 1.0.9