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 }