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

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

Revision 5050 - (download) (as text) (annotate)
Thu Jun 28 02:17:32 2007 UTC (12 years, 7 months ago) by dpvc
File size: 7869 byte(s)
```Updated context method calls.
```

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

 aubreyja at gmail dot com ViewVC Help Powered by ViewVC 1.0.9