Revision 7
Added by Willibald K. over 8 years ago
Expression.java | ||
---|---|---|
1 |
/**
|
|
2 |
*
|
|
3 |
* OOAS Compiler
|
|
4 |
*
|
|
5 |
* Copyright 2015, AIT Austrian Institute of Technology.
|
|
6 |
* This code is based on the C# Version of the OOAS Compiler, which is
|
|
7 |
* copyright 2015 by the Institute of Software Technology, Graz University
|
|
8 |
* of Technology with portions copyright by the AIT Austrian Institute of
|
|
9 |
* Technology. All rights reserved.
|
|
10 |
*
|
|
11 |
* SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
|
|
12 |
*
|
|
13 |
* If you modify the file please update the list of contributors below to in-
|
|
14 |
* clude your name. Please also stick to the coding convention of using TABs
|
|
15 |
* to do the basic (block-level) indentation and spaces for anything after
|
|
16 |
* that. (Enable the display of special chars and it should be pretty obvious
|
|
17 |
* what this means.) Also, remove all trailing whitespace.
|
|
18 |
*
|
|
19 |
* Contributors:
|
|
20 |
* Willibald Krenn (AIT)
|
|
21 |
* Stephan Zimmerer (AIT)
|
|
22 |
* Markus Demetz (AIT)
|
|
23 |
* Christoph Czurda (AIT)
|
|
24 |
*
|
|
25 |
*/
|
|
1 |
/** |
|
2 |
* |
|
3 |
* OOAS Compiler |
|
4 |
* |
|
5 |
* Copyright 2015, AIT Austrian Institute of Technology. |
|
6 |
* This code is based on the C# Version of the OOAS Compiler, which is |
|
7 |
* copyright 2015 by the Institute of Software Technology, Graz University |
|
8 |
* of Technology with portions copyright by the AIT Austrian Institute of |
|
9 |
* Technology. All rights reserved. |
|
10 |
* |
|
11 |
* SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED. |
|
12 |
* |
|
13 |
* If you modify the file please update the list of contributors below to in- |
|
14 |
* clude your name. Please also stick to the coding convention of using TABs |
|
15 |
* to do the basic (block-level) indentation and spaces for anything after |
|
16 |
* that. (Enable the display of special chars and it should be pretty obvious |
|
17 |
* what this means.) Also, remove all trailing whitespace. |
|
18 |
* |
|
19 |
* Contributors: |
|
20 |
* Willibald Krenn (AIT) |
|
21 |
* Stephan Zimmerer (AIT) |
|
22 |
* Markus Demetz (AIT) |
|
23 |
* Christoph Czurda (AIT) |
|
24 |
* |
|
25 |
*/ |
|
26 | 26 |
|
27 | 27 |
|
28 |
package org.momut.ooas.ast.expressions; |
|
29 |
|
|
30 |
import java.util.ArrayList; |
|
31 |
import java.util.List; |
|
28 |
package org.momut.ooas.ast.expressions; |
|
32 | 29 |
|
30 |
import java.util.ArrayList; |
|
31 |
import java.util.List; |
|
32 |
|
|
33 | 33 |
import org.momut.ooas.ast.AstNode; |
34 | 34 |
import org.momut.ooas.ast.AstNodeTypeEnum; |
35 | 35 |
import org.momut.ooas.ast.IAst; |
... | ... | |
52 | 52 |
import org.momut.ooas.utils.exceptions.ArgumentException; |
53 | 53 |
import org.momut.ooas.utils.exceptions.NotImplementedException; |
54 | 54 |
import org.momut.ooas.visitors.OoaPrintVisitor; |
55 |
|
|
56 |
/////////////////////////////////////////////// |
|
57 |
/// Expressions |
|
58 |
/// |
|
59 |
/// Note: Since we allow expression of the form |
|
60 |
/// myTuple(a,b) = hd x, where a and b are newly |
|
61 |
/// introduced placeholders, the expression knows |
|
62 |
/// about local variables. |
|
63 |
/// Scoping: Consider following expression |
|
64 |
/// 3 > a and myTuple(b,d) = hd e and b < 5 |
|
65 |
/// which gives |
|
66 |
/// and |
|
67 |
/// / \ |
|
68 |
/// / and |
|
69 |
/// / / \ |
|
70 |
/// > = < |
|
71 |
/// / \ / \ / \ |
|
72 |
/// 3 a (b,d) e b 5 |
|
73 |
/// the scope of b and d is defined by the binary |
|
74 |
/// expression that has the leaf within its left child |
|
75 |
/// (== the second 'and'). |
|
76 |
/// Local variables may only be introduced in constructors |
|
77 |
/// of sets, lists, and tuples. Therefore the type is |
|
78 |
/// known. |
|
79 |
|
|
80 |
|
|
81 |
public abstract class Expression extends AstNode implements IAst |
|
82 |
{ |
|
83 |
protected ExpressionKind m_kind; |
|
84 |
protected UlyssesType m_type; |
|
85 |
protected int m_line; |
|
86 |
protected int m_pos; |
|
87 |
protected SymbolTable m_freeVariables; |
|
88 |
protected ArrayList<FunctionIdentifier> m_callTargets; |
|
89 |
|
|
90 |
public ExpressionKind kind() { return m_kind; } |
|
91 |
public UlyssesType type() { return m_type; } |
|
92 |
public int line() { return m_line; } |
|
93 |
public int pos() { return m_pos; } |
|
94 |
public SymbolTable freeVariables() { return m_freeVariables; } |
|
95 |
public List<FunctionIdentifier> callTargets() { return m_callTargets; } |
|
96 |
|
|
97 |
public Expression(ExpressionKind aKind, int line, int pos) |
|
98 |
{ |
|
99 |
m_kind = aKind; |
|
100 |
m_line = line; |
|
101 |
m_pos = pos; |
|
102 |
m_callTargets = new ArrayList<FunctionIdentifier>(); |
|
103 |
} |
|
104 |
|
|
105 |
public Expression(Expression toCopy) |
|
106 |
{ |
|
107 |
m_kind = toCopy.m_kind; |
|
108 |
m_line = toCopy.m_line; |
|
109 |
m_pos = toCopy.m_pos; |
|
110 |
m_callTargets = new ArrayList<FunctionIdentifier>(toCopy.callTargets()); |
|
111 |
m_type = toCopy.m_type; |
|
112 |
m_freeVariables = new SymbolTable(toCopy.m_freeVariables); |
|
113 |
} |
|
114 |
|
|
115 |
public /*virtual*/ Expression Clone() |
|
116 |
{ |
|
117 |
throw new NotImplementedException(); |
|
118 |
} |
|
119 |
|
|
120 |
public void SetType(UlyssesType aType) |
|
121 |
{ |
|
122 |
if (aType == null) |
|
123 |
throw new ArgumentException(); |
|
124 |
m_type = aType; |
|
125 |
} |
|
126 |
|
|
127 |
public void SetFreeVariables(SymbolTable aSymTab) |
|
128 |
{ |
|
129 |
m_freeVariables = aSymTab; |
|
130 |
} |
|
131 |
|
|
132 |
public ArrayList<ExpressionVariableIdentifier> GetUninitializedFreeVariables() |
|
133 |
{ |
|
134 |
final ArrayList<ExpressionVariableIdentifier> result = new ArrayList<ExpressionVariableIdentifier>(); |
|
135 |
if (m_freeVariables != null) |
|
136 |
for(final Identifier v: m_freeVariables.symbolList()) |
|
137 |
{ |
|
138 |
final ExpressionVariableIdentifier id = (ExpressionVariableIdentifier)v; |
|
139 |
if (id.initialized() == false) |
|
140 |
result.add(id); |
|
141 |
} |
|
142 |
return result; |
|
143 |
} |
|
144 |
|
|
145 |
|
|
146 |
@Override |
|
147 |
public AstNodeTypeEnum nodeType() { return AstNodeTypeEnum.expression; } |
|
148 |
|
|
149 |
@Override |
|
150 |
public /*virtual*/ void Accept(IAstVisitor visitor) |
|
151 |
{ |
|
152 |
throw new NotImplementedException(); |
|
153 |
} |
|
154 |
|
|
155 |
|
|
156 |
/// <summary> |
|
157 |
/// Calculates the arithmetic cover, i.e. the return type of the operation, given two types. |
|
158 |
/// This is different from the cover-method defined at the type level. |
|
159 |
/// Note: We do saturating operations on the type boundaries. |
|
160 |
/// </summary> |
|
161 |
public static UlyssesType ArithmeticCover(UlyssesType type1, UlyssesType type2, ExpressionKind op) |
|
162 |
{ |
|
163 |
if (!type1.IsNumeric() || (type2 != null && !type2.IsNumeric())) |
|
164 |
throw new ArgumentException(); |
|
165 |
|
|
166 |
if (type1 instanceof ValuedEnumType) |
|
167 |
type1 = ((ValuedEnumType)type1).getIntType(); |
|
168 |
if (type2 instanceof ValuedEnumType) |
|
169 |
type2 = ((ValuedEnumType)type2).getIntType(); |
|
170 |
|
|
171 |
AbstractRange result; |
|
172 |
AbstractRange rangeType1 = null; |
|
173 |
AbstractRange rangeType2 = null; |
|
174 |
AbstractOperations operations; |
|
175 |
final boolean resultIsFloat = type1.kind() == TypeKind.FloatType |
|
176 |
|| op == ExpressionKind.div |
|
177 |
|| (type2 != null && type2.kind() == TypeKind.FloatType); |
|
178 |
if (resultIsFloat) |
|
179 |
{ |
|
180 |
rangeType1 = new DoubleRange( |
|
181 |
type1.kind() == TypeKind.IntType ? ((IntType)type1).rangeHigh() : ((FloatType)type1).high(), |
|
182 |
type1.kind() == TypeKind.IntType ? ((IntType)type1).rangeLow() : ((FloatType)type1).low()); |
|
183 |
if (type2 != null) |
|
184 |
{ |
|
185 |
rangeType2 = new DoubleRange( |
|
186 |
type2.kind() == TypeKind.IntType ? ((IntType)type2).rangeHigh() : ((FloatType)type2).high(), |
|
187 |
type2.kind() == TypeKind.IntType ? ((IntType)type2).rangeLow() : ((FloatType)type2).low()); |
|
188 |
} |
|
189 |
operations = new SaturatedDoubleOperations(); |
|
190 |
} |
|
191 |
else |
|
192 |
{ |
|
193 |
rangeType1 = new IntegerRange(((IntType)type1).rangeHigh(), ((IntType)type1).rangeLow()); |
|
194 |
rangeType2 = new IntegerRange(((IntType)type2).rangeHigh(), ((IntType)type2).rangeLow()); |
|
195 |
operations = new SaturatedIntegerOperations(); |
|
196 |
} |
|
197 |
|
|
198 |
switch (op) |
|
199 |
{ |
|
200 |
case pow: |
|
201 |
case prod: |
|
202 |
case unminus: |
|
203 |
case unplus: |
|
204 |
case minus: |
|
205 |
case sum: |
|
206 |
case div: |
|
207 |
result = operations.GenericArithmeticCover(rangeType1, rangeType2, op); |
|
208 |
break; |
|
209 |
|
|
210 |
case idiv: |
|
211 |
if (resultIsFloat) |
|
212 |
throw new ArgumentException(); |
|
213 |
assert(type2 != null); |
|
214 |
result = operations.GenericArithmeticCover(rangeType1, rangeType2, op); |
|
215 |
break; |
|
216 |
|
|
217 |
case mod: |
|
218 |
if (resultIsFloat) |
|
219 |
throw new ArgumentException(); |
|
220 |
assert(type2 != null); |
|
221 |
// FIXME: see http://mathforum.org/library/drmath/view/52343.html; LLVM only supports rem! |
|
222 |
final boolean isSigned = ((IntegerRange)rangeType2).min < 0 || ((IntegerRange)rangeType1).min < 0; |
|
223 |
result = new IntegerRange(((IntegerRange)rangeType2).max - 1, isSigned ? -((IntegerRange)rangeType2).max - 1 : 0); |
|
224 |
break; |
|
225 |
|
|
226 |
default: |
|
227 |
throw new NotImplementedException(); |
|
228 |
} |
|
229 |
|
|
230 |
if (resultIsFloat) |
|
231 |
return new FloatType( |
|
232 |
((DoubleRange)result).min, |
|
233 |
((DoubleRange)result).max, |
|
234 |
FloatType.defaultPrecision(), |
|
235 |
null); |
|
236 |
else |
|
237 |
// this is crude, but see whether it works.. |
|
238 |
return new IntType( |
|
239 |
((IntegerRange)result).min, |
|
240 |
((IntegerRange)result).max, |
|
241 |
null); |
|
242 |
} |
|
243 |
|
|
244 |
|
|
245 |
@Override |
|
246 |
public String toString() |
|
247 |
{ |
|
248 |
return toString(new OoaPrintVisitor(null)); |
|
249 |
} |
|
250 |
|
|
251 |
public String toString(OoaPrintVisitor aFormatter) { |
|
252 |
this.Accept(aFormatter); |
|
253 |
return aFormatter.toString(); |
|
254 |
} |
|
255 |
} |
|
256 |
|
|
55 |
|
|
56 |
/////////////////////////////////////////////// |
|
57 |
/// Expressions |
|
58 |
/// |
|
59 |
/// Note: Since we allow expression of the form |
|
60 |
/// myTuple(a,b) = hd x, where a and b are newly |
|
61 |
/// introduced placeholders, the expression knows |
|
62 |
/// about local variables. |
|
63 |
/// Scoping: Consider following expression |
|
64 |
/// 3 > a and myTuple(b,d) = hd e and b < 5 |
|
65 |
/// which gives |
|
66 |
/// and |
|
67 |
/// / \ |
|
68 |
/// / and |
|
69 |
/// / / \ |
|
70 |
/// > = < |
|
71 |
/// / \ / \ / \ |
|
72 |
/// 3 a (b,d) e b 5 |
|
73 |
/// the scope of b and d is defined by the binary |
|
74 |
/// expression that has the leaf within its left child |
|
75 |
/// (== the second 'and'). |
|
76 |
/// Local variables may only be introduced in constructors |
|
77 |
/// of sets, lists, and tuples. Therefore the type is |
|
78 |
/// known. |
|
79 |
|
|
80 |
|
|
81 |
public abstract class Expression extends AstNode implements IAst |
|
82 |
{ |
|
83 |
protected ExpressionKind m_kind; |
|
84 |
protected UlyssesType m_type; |
|
85 |
protected int m_line; |
|
86 |
protected int m_pos; |
|
87 |
protected SymbolTable m_freeVariables; |
|
88 |
protected ArrayList<FunctionIdentifier> m_callTargets; |
|
89 |
|
|
90 |
public ExpressionKind kind() { return m_kind; } |
|
91 |
public UlyssesType type() { return m_type; } |
|
92 |
public int line() { return m_line; } |
|
93 |
public int pos() { return m_pos; } |
|
94 |
public SymbolTable freeVariables() { return m_freeVariables; } |
|
95 |
public List<FunctionIdentifier> callTargets() { return m_callTargets; } |
|
96 |
|
|
97 |
public Expression(ExpressionKind aKind, int line, int pos) |
|
98 |
{ |
|
99 |
m_kind = aKind; |
|
100 |
m_line = line; |
|
101 |
m_pos = pos; |
|
102 |
m_callTargets = new ArrayList<FunctionIdentifier>(); |
|
103 |
} |
|
104 |
|
|
105 |
public Expression(Expression toCopy) |
|
106 |
{ |
|
107 |
m_kind = toCopy.m_kind; |
|
108 |
m_line = toCopy.m_line; |
|
109 |
m_pos = toCopy.m_pos; |
|
110 |
m_callTargets = new ArrayList<FunctionIdentifier>(toCopy.callTargets()); |
|
111 |
m_type = toCopy.m_type; |
|
112 |
m_freeVariables = new SymbolTable(toCopy.m_freeVariables); |
|
113 |
} |
|
114 |
|
|
115 |
public /*virtual*/ Expression Clone() |
|
116 |
{ |
|
117 |
throw new NotImplementedException(); |
|
118 |
} |
|
119 |
|
|
120 |
public void SetType(UlyssesType aType) |
|
121 |
{ |
|
122 |
if (aType == null) |
|
123 |
throw new ArgumentException(); |
|
124 |
m_type = aType; |
|
125 |
} |
|
126 |
|
|
127 |
public void SetFreeVariables(SymbolTable aSymTab) |
|
128 |
{ |
|
129 |
m_freeVariables = aSymTab; |
|
130 |
} |
|
131 |
|
|
132 |
public ArrayList<ExpressionVariableIdentifier> GetUninitializedFreeVariables() |
|
133 |
{ |
|
134 |
final ArrayList<ExpressionVariableIdentifier> result = new ArrayList<ExpressionVariableIdentifier>(); |
|
135 |
if (m_freeVariables != null) |
|
136 |
for(final Identifier v: m_freeVariables.symbolList()) |
|
137 |
{ |
|
138 |
final ExpressionVariableIdentifier id = (ExpressionVariableIdentifier)v; |
|
139 |
if (id.initialized() == false) |
|
140 |
result.add(id); |
|
141 |
} |
|
142 |
return result; |
|
143 |
} |
|
144 |
|
|
145 |
|
|
146 |
@Override |
|
147 |
public AstNodeTypeEnum nodeType() { return AstNodeTypeEnum.expression; } |
|
148 |
|
|
149 |
@Override |
|
150 |
public /*virtual*/ void Accept(IAstVisitor visitor) |
|
151 |
{ |
|
152 |
throw new NotImplementedException(); |
|
153 |
} |
|
154 |
|
|
155 |
|
|
156 |
/// <summary> |
|
157 |
/// Calculates the arithmetic cover, i.e. the return type of the operation, given two types. |
|
158 |
/// This is different from the cover-method defined at the type level. |
|
159 |
/// Note: We do saturating operations on the type boundaries. |
|
160 |
/// </summary> |
|
161 |
public static UlyssesType ArithmeticCover(UlyssesType type1, UlyssesType type2, ExpressionKind op) |
|
162 |
{ |
|
163 |
if (!type1.IsNumeric() || (type2 != null && !type2.IsNumeric())) |
|
164 |
throw new ArgumentException(); |
|
165 |
|
|
166 |
if (type1 instanceof ValuedEnumType) |
|
167 |
type1 = ((ValuedEnumType)type1).getIntType(); |
|
168 |
if (type2 instanceof ValuedEnumType) |
|
169 |
type2 = ((ValuedEnumType)type2).getIntType(); |
|
170 |
|
|
171 |
AbstractRange result; |
|
172 |
AbstractRange rangeType1 = null; |
|
173 |
AbstractRange rangeType2 = null; |
|
174 |
AbstractOperations operations; |
|
175 |
final boolean resultIsFloat = type1.kind() == TypeKind.FloatType |
|
176 |
|| op == ExpressionKind.div |
|
177 |
|| (type2 != null && type2.kind() == TypeKind.FloatType); |
|
178 |
if (resultIsFloat) |
|
179 |
{ |
|
180 |
rangeType1 = new DoubleRange( |
|
181 |
type1.kind() == TypeKind.IntType ? ((IntType)type1).rangeHigh() : ((FloatType)type1).high(), |
|
182 |
type1.kind() == TypeKind.IntType ? ((IntType)type1).rangeLow() : ((FloatType)type1).low()); |
|
183 |
if (type2 != null) |
|
184 |
{ |
|
185 |
rangeType2 = new DoubleRange( |
|
186 |
type2.kind() == TypeKind.IntType ? ((IntType)type2).rangeHigh() : ((FloatType)type2).high(), |
|
187 |
type2.kind() == TypeKind.IntType ? ((IntType)type2).rangeLow() : ((FloatType)type2).low()); |
|
188 |
} |
|
189 |
operations = new SaturatedDoubleOperations(); |
|
190 |
} |
|
191 |
else |
|
192 |
{ |
|
193 |
rangeType1 = new IntegerRange(((IntType)type1).rangeHigh(), ((IntType)type1).rangeLow()); |
|
194 |
rangeType2 = new IntegerRange(((IntType)type2).rangeHigh(), ((IntType)type2).rangeLow()); |
|
195 |
operations = new SaturatedIntegerOperations(); |
|
196 |
} |
|
197 |
|
|
198 |
switch (op) |
|
199 |
{ |
|
200 |
case pow: |
|
201 |
case prod: |
|
202 |
case unminus: |
|
203 |
case unplus: |
|
204 |
case minus: |
|
205 |
case sum: |
|
206 |
case div: |
|
207 |
result = operations.GenericArithmeticCover(rangeType1, rangeType2, op); |
|
208 |
break; |
|
209 |
|
|
210 |
case idiv: |
|
211 |
if (resultIsFloat) |
|
212 |
throw new ArgumentException(); |
|
213 |
assert(type2 != null); |
|
214 |
result = operations.GenericArithmeticCover(rangeType1, rangeType2, op); |
|
215 |
break; |
|
216 |
|
|
217 |
case mod: |
|
218 |
if (resultIsFloat) |
|
219 |
throw new ArgumentException(); |
|
220 |
assert(type2 != null); |
|
221 |
// FIXME: see http://mathforum.org/library/drmath/view/52343.html; LLVM only supports rem! |
|
222 |
final boolean isSigned = ((IntegerRange)rangeType2).min < 0 || ((IntegerRange)rangeType1).min < 0; |
|
223 |
result = new IntegerRange(((IntegerRange)rangeType2).max - 1, isSigned ? -((IntegerRange)rangeType2).max - 1 : 0); |
|
224 |
break; |
|
225 |
|
|
226 |
default: |
|
227 |
throw new NotImplementedException(); |
|
228 |
} |
|
229 |
|
|
230 |
if (resultIsFloat) |
|
231 |
return new FloatType( |
|
232 |
((DoubleRange)result).min, |
|
233 |
((DoubleRange)result).max, |
|
234 |
FloatType.defaultPrecision(), |
|
235 |
null); |
|
236 |
else |
|
237 |
// this is crude, but see whether it works.. |
|
238 |
return new IntType( |
|
239 |
((IntegerRange)result).min, |
|
240 |
((IntegerRange)result).max, |
|
241 |
null); |
|
242 |
} |
|
243 |
|
|
244 |
|
|
245 |
@Override |
|
246 |
public String toString() |
|
247 |
{ |
|
248 |
return toString(new OoaPrintVisitor(null)); |
|
249 |
} |
|
250 |
|
|
251 |
public String toString(OoaPrintVisitor aFormatter) { |
|
252 |
this.Accept(aFormatter); |
|
253 |
return aFormatter.toString(); |
|
254 |
} |
|
255 |
} |
|
256 |
|
Also available in: Unified diff
changing java, cpp, hpp files to unix line endings