1 /********************************************************************************
2 *
3 * Copyright (c) 2008 Fujitsu Services Ltd.
4 *
5 * Author: Nick Battle
6 *
7 * This file is part of VDMJ.
8 *
9 * VDMJ is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * VDMJ is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
21 *
22 ******************************************************************************/
23
24 package org.overturetool.vdmj.statements;
25
26 import org.overturetool.vdmj.definitions.MultiBindListDefinition;
27 import org.overturetool.vdmj.expressions.Expression;
28 import org.overturetool.vdmj.lex.LexLocation;
29 import org.overturetool.vdmj.patterns.MultipleBind;
30 import org.overturetool.vdmj.patterns.Pattern;
31 import org.overturetool.vdmj.pog.LetBeExistsObligation;
32 import org.overturetool.vdmj.pog.POContextStack;
33 import org.overturetool.vdmj.pog.ProofObligationList;
34 import org.overturetool.vdmj.runtime.Context;
35 import org.overturetool.vdmj.runtime.ValueException;
36 import org.overturetool.vdmj.typechecker.Environment;
37 import org.overturetool.vdmj.typechecker.FlatCheckedEnvironment;
38 import org.overturetool.vdmj.typechecker.NameScope;
39 import org.overturetool.vdmj.types.BooleanType;
40 import org.overturetool.vdmj.types.Type;
41 import org.overturetool.vdmj.types.TypeSet;
42 import org.overturetool.vdmj.values.NameValuePair;
43 import org.overturetool.vdmj.values.NameValuePairList;
44 import org.overturetool.vdmj.values.Quantifier;
45 import org.overturetool.vdmj.values.QuantifierList;
46 import org.overturetool.vdmj.values.Value;
47 import org.overturetool.vdmj.values.ValueList;
48
49 public class LetBeStStatement extends Statement
50 {
51 private static final long serialVersionUID = 1L;
52 public final MultipleBind bind;
53 public final Expression suchThat;
54 public final Statement statement;
55 private MultiBindListDefinition def = null;
56
57 public LetBeStStatement(LexLocation location,
58 MultipleBind bind, Expression suchThat, Statement statement)
59 {
60 super(location);
61 this.bind = bind;
62 this.suchThat = suchThat;
63 this.statement = statement;
64 }
65
66 @Override
67 public String toString()
68 {
69 return "let " + bind +
70 (suchThat == null ? "" : " be st " + suchThat) + " in " + statement;
71 }
72
73 @Override
74 public String kind()
75 {
76 return "let be st";
77 }
78
79 @Override
80 public Type typeCheck(Environment base, NameScope scope)
81 {
82 def = new MultiBindListDefinition(location, bind.getMultipleBindList());
83 def.typeCheck(base, scope);
84 Environment local = new FlatCheckedEnvironment(def, base);
85
86 if (suchThat != null && !suchThat.typeCheck(local, null, scope).isType(BooleanType.class))
87 {
88 report(3225, "Such that clause is not boolean");
89 }
90
91 Type r = statement.typeCheck(local, scope);
92 local.unusedCheck();
93 return r;
94 }
95
96 @Override
97 public TypeSet exitCheck()
98 {
99 return statement.exitCheck();
100 }
101
102 @Override
103 public Statement findStatement(int lineno)
104 {
105 Statement found = super.findStatement(lineno);
106 if (found != null) return found;
107 return statement.findStatement(lineno);
108 }
109
110 @Override
111 public Expression findExpression(int lineno)
112 {
113 Expression found = suchThat.findExpression(lineno);
114 if (found != null) return found;
115 return statement.findExpression(lineno);
116 }
117
118 @Override
119 public Value eval(Context ctxt)
120 {
121 breakpoint.check(location, ctxt);
122 QuantifierList quantifiers = new QuantifierList();
123
124 for (MultipleBind mb: def.bindings)
125 {
126 ValueList bvals = mb.getBindValues(ctxt);
127
128 for (Pattern p: mb.plist)
129 {
130 Quantifier q = new Quantifier(p, bvals);
131 quantifiers.add(q);
132 }
133 }
134
135 quantifiers.init();
136
137 try
138 {
139 while (quantifiers.hasNext(ctxt))
140 {
141 Context evalContext = new Context(location, "let be st statement", ctxt);
142 NameValuePairList nvpl = quantifiers.next();
143 boolean matches = true;
144
145 for (NameValuePair nvp: nvpl)
146 {
147 Value v = evalContext.get(nvp.name);
148
149 if (v == null)
150 {
151 evalContext.put(nvp.name, nvp.value);
152 }
153 else
154 {
155 if (!v.equals(nvp.value))
156 {
157 matches = false;
158 break;
159 }
160 }
161 }
162
163 if (matches &&
164 (suchThat == null || suchThat.eval(evalContext).boolValue(ctxt)))
165 {
166 return statement.eval(evalContext);
167 }
168 }
169 }
170 catch (ValueException e)
171 {
172 abort(e);
173 }
174
175 return abort(4040, "Let be st found no applicable bindings", ctxt);
176 }
177
178 @Override
179 public ProofObligationList getProofObligations(POContextStack ctxt)
180 {
181 ProofObligationList obligations = new ProofObligationList();
182 obligations.add(new LetBeExistsObligation(this, ctxt));
183 obligations.addAll(bind.getProofObligations(ctxt));
184
185 if (suchThat != null)
186 {
187 obligations.addAll(suchThat.getProofObligations(ctxt));
188 }
189
190 obligations.addAll(statement.getProofObligations(ctxt));
191
192 return obligations;
193 }
194 }