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.Definition;
27 import org.overturetool.vdmj.expressions.Expression;
28 import org.overturetool.vdmj.expressions.ExpressionList;
29 import org.overturetool.vdmj.lex.LexNameToken;
30 import org.overturetool.vdmj.pog.POContextStack;
31 import org.overturetool.vdmj.pog.ProofObligationList;
32 import org.overturetool.vdmj.runtime.Context;
33 import org.overturetool.vdmj.runtime.ValueException;
34 import org.overturetool.vdmj.typechecker.Environment;
35 import org.overturetool.vdmj.typechecker.NameScope;
36 import org.overturetool.vdmj.typechecker.TypeComparator;
37 import org.overturetool.vdmj.types.FunctionType;
38 import org.overturetool.vdmj.types.OperationType;
39 import org.overturetool.vdmj.types.Type;
40 import org.overturetool.vdmj.types.TypeList;
41 import org.overturetool.vdmj.types.TypeSet;
42 import org.overturetool.vdmj.types.UnknownType;
43 import org.overturetool.vdmj.util.Utils;
44 import org.overturetool.vdmj.values.FunctionValue;
45 import org.overturetool.vdmj.values.OperationValue;
46 import org.overturetool.vdmj.values.Value;
47 import org.overturetool.vdmj.values.ValueList;
48
49 public class CallStatement extends Statement
50 {
51 private static final long serialVersionUID = 1L;
52 public final LexNameToken name;
53 public final ExpressionList args;
54
55 public CallStatement(LexNameToken name, ExpressionList args)
56 {
57 super(name.location);
58 this.name = name;
59 this.args = args;
60 }
61
62 @Override
63 public String toString()
64 {
65 return "call " + name + "(" + Utils.listToString(args) + ")";
66 }
67
68 @Override
69 public String kind()
70 {
71 return "call";
72 }
73
74 @Override
75 public Type typeCheck(Environment env, NameScope scope)
76 {
77 TypeList atypes = getArgTypes(env, scope);
78
79 if (env.isVDMPP())
80 {
81 name.setTypeQualifier(atypes);
82 }
83
84 Definition opdef = env.findName(name, scope);
85
86 if (opdef == null)
87 {
88 report(3213, "Operation " + name + " is not in scope");
89 env.listAlternatives(name);
90 return new UnknownType(location);
91 }
92
93 if (!opdef.isStatic() && env.isStatic())
94 {
95 report(3214, "Cannot call " + name + " from static context");
96 return new UnknownType(location);
97 }
98
99 Type type = opdef.getType();
100
101 if (type.isOperation())
102 {
103 OperationType optype = type.getOperation();
104 optype.typeResolve(env, null);
105
106
107
108
109 if (env.isVDMPP())
110 {
111 name.setTypeQualifier(optype.parameters);
112 }
113
114 checkArgTypes(optype.parameters, atypes);
115 return optype.result;
116 }
117 else if (type.isFunction())
118 {
119
120
121
122 FunctionType ftype = type.getFunction();
123 ftype.typeResolve(env, null);
124
125
126
127
128 if (env.isVDMPP())
129 {
130 name.setTypeQualifier(ftype.parameters);
131 }
132
133 checkArgTypes(ftype.parameters, atypes);
134 return ftype.result;
135 }
136 else
137 {
138 report(3210, "Name is neither a function nor an operation");
139 return new UnknownType(location);
140 }
141 }
142
143 @Override
144 public TypeSet exitCheck()
145 {
146
147 return new TypeSet(new UnknownType(location));
148 }
149
150 private TypeList getArgTypes(Environment env, NameScope scope)
151 {
152 TypeList types = new TypeList();
153
154 for (Expression a: args)
155 {
156 types.add(a.typeCheck(env, null, scope));
157 }
158
159 return types;
160 }
161
162 private void checkArgTypes(TypeList ptypes, TypeList atypes)
163 {
164 if (ptypes.size() != atypes.size())
165 {
166 report(3216, "Expecting " + ptypes.size() + " arguments");
167 }
168 else
169 {
170 int i=0;
171
172 for (Type atype: atypes)
173 {
174 Type ptype = ptypes.get(i++);
175
176 if (!TypeComparator.compatible(ptype, atype))
177 {
178 atype.report(3217, "Unexpected type for argument " + i);
179 detail2("Expected", ptype, "Actual", atype);
180 }
181 }
182 }
183 }
184
185 @Override
186 public Value eval(Context ctxt)
187 {
188 breakpoint.check(location, ctxt);
189
190 try
191 {
192 Value v = ctxt.lookup(name).deref();
193
194 if (v instanceof OperationValue)
195 {
196 OperationValue op = v.operationValue(ctxt);
197 ValueList argValues = new ValueList();
198
199 for (Expression arg: args)
200 {
201 argValues.add(arg.eval(ctxt));
202 }
203
204 return op.eval(argValues, ctxt);
205 }
206 else
207 {
208 FunctionValue fn = v.functionValue(ctxt);
209 ValueList argValues = new ValueList();
210
211 for (Expression arg: args)
212 {
213 argValues.add(arg.eval(ctxt));
214 }
215
216 return fn.eval(location, argValues, ctxt);
217 }
218 }
219 catch (ValueException e)
220 {
221 return abort(e);
222 }
223 }
224
225 @Override
226 public Expression findExpression(int lineno)
227 {
228 return args.findExpression(lineno);
229 }
230
231 @Override
232 public ProofObligationList getProofObligations(POContextStack ctxt)
233 {
234 ProofObligationList obligations = new ProofObligationList();
235
236 for (Expression exp: args)
237 {
238 obligations.addAll(exp.getProofObligations(ctxt));
239 }
240
241 return obligations;
242 }
243 }