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.lex.LexNameToken;
28  import org.overturetool.vdmj.runtime.Context;
29  import org.overturetool.vdmj.runtime.ValueException;
30  import org.overturetool.vdmj.typechecker.Environment;
31  import org.overturetool.vdmj.typechecker.NameScope;
32  import org.overturetool.vdmj.types.ClassType;
33  import org.overturetool.vdmj.types.Field;
34  import org.overturetool.vdmj.types.RecordType;
35  import org.overturetool.vdmj.types.Type;
36  import org.overturetool.vdmj.types.TypeList;
37  import org.overturetool.vdmj.types.TypeSet;
38  import org.overturetool.vdmj.types.UnknownType;
39  import org.overturetool.vdmj.values.ObjectValue;
40  import org.overturetool.vdmj.values.RecordValue;
41  import org.overturetool.vdmj.values.Value;
42  
43  public class ObjectFieldDesignator extends ObjectDesignator
44  {
45  	private static final long serialVersionUID = 1L;
46  	public final ObjectDesignator object;
47  	public String classname;
48  	public final String fieldname;
49  
50  	private LexNameToken field = null;
51  
52  	public ObjectFieldDesignator(
53  		ObjectDesignator object, String classname, String fieldname)
54  	{
55  		super(object.location);
56  		this.object = object;
57  		this.classname = classname;
58  		this.fieldname = fieldname;
59  	}
60  
61  	@Override
62  	public String toString()
63  	{
64  		return object + "." +
65  			(classname == null ? "" : classname + "`") + fieldname;
66  	}
67  
68  	@Override
69  	public Type typeCheck(Environment env, TypeList qualifiers)
70  	{
71  		Type type = object.typeCheck(env, qualifiers);
72  		TypeSet result = new TypeSet();
73  		boolean unique = !type.isUnion();
74  
75  		if (type.isClass())
76  		{
77  			ClassType ctype = type.getClassType();
78  			String cname = (classname == null) ? ctype.name.name : classname;
79  
80  			field = new LexNameToken(cname, fieldname, location);
81  			field.setTypeQualifier(qualifiers);
82  			Definition fdef = ctype.classdef.findName(field, NameScope.NAMESANDSTATE);
83  
84  			if (fdef == null)
85  			{
86  				concern(unique, 3260, "Unknown class member name, '" + field + "'");
87  				result.add(new UnknownType(location));
88  			}
89  			else
90  			{
91  				result.add(fdef.getType());
92  			}
93  		}
94  
95  		if (type.isRecord())
96  		{
97  			RecordType rec = type.getRecord();
98  			Field rf = rec.findField(fieldname);
99  
100 			if (rf == null)
101 			{
102 				concern(unique, 3261, "Unknown field name, '" + fieldname + "'");
103 				result.add(new UnknownType(location));
104 			}
105 			else
106 			{
107 				result.add(rf.type);
108 			}
109 		}
110 
111 		if (result.isEmpty())
112 		{
113 			report(3262, "Field assignment is not of a class or record type");
114 			detail2("Expression", object, "Type", type);
115 			return new UnknownType(location);
116 		}
117 
118 		return result.getType(location);
119 	}
120 
121 	@Override
122 	public Value eval(Context ctxt)
123 	{
124 		try
125 		{
126 			Value val = object.eval(ctxt).deref();
127 
128 			if (val instanceof ObjectValue && field != null)
129 			{
130     			ObjectValue ov = val.objectValue(ctxt);
131     			Value rv = ov.get(field, (classname != null));
132 
133     			if (rv == null)
134     			{
135     				abort(4045, "Object does not contain value for field: " + field, ctxt);
136     			}
137 
138     			return rv;
139 			}
140 			else if (val instanceof RecordValue)
141 			{
142 				RecordValue rec = val.recordValue(ctxt);
143 				Value result = rec.fieldmap.get(fieldname);
144 
145 				if (result == null)
146 				{
147 					abort(4046, "No such field: " + fieldname, ctxt);
148 				}
149 
150 				return result;
151 			}
152 			else
153 			{
154 				return abort(4020,
155 					"State value is neither a record nor an object", ctxt);
156 			}
157 		}
158 		catch (ValueException e)
159 		{
160 			return abort(e);
161 		}
162 	}
163 }