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 }