View Javadoc

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     		// Reset the name's qualifier with the actual operation type so
107     		// that runtime search has a simple TypeComparator call.
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 			// This is the case where a function is called as an operation without
120 			// a "return" statement.
121 
122     		FunctionType ftype = type.getFunction();
123     		ftype.typeResolve(env, null);
124 
125     		// Reset the name's qualifier with the actual function type so
126     		// that runtime search has a simple TypeComparator call.
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 		// TODO We don't know what an operation call will raise
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 }