Project

General

Profile

Revision 7

Added by Willibald K. over 8 years ago

changing java, cpp, hpp files to unix line endings

View differences:

OoaResolveExpressionsVisitor.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.visitors;
29

  
30
import java.util.ArrayList;
31
import java.util.Iterator;
32
import java.util.LinkedList;
33
import java.util.Stack;
28
package org.momut.ooas.visitors;
34 29

  
30
import java.util.ArrayList;
31
import java.util.Iterator;
32
import java.util.LinkedList;
33
import java.util.Stack;
34

  
35 35
import org.momut.ooas.ast.AstNodeTypeEnum;
36 36
import org.momut.ooas.ast.IAst;
37 37
import org.momut.ooas.ast.expressions.AccessExpression;
......
92 92
import org.momut.ooas.parser.SymbolTable;
93 93
import org.momut.ooas.utils.exceptions.ArgumentException;
94 94
import org.momut.ooas.utils.exceptions.NotImplementedException;
95

  
96
/// <summary>
97
/// Requires: ReplaceOpaqueVisitor
98
///
99
/// After we have an AST without any Opaquetypes, we still need to replace all the
100
/// UnresolvedIdentifierExpressions. We also need to compute the expression types,
101
/// which is also necessary to resolve all the identifiers. So, this visitor
102
/// goes over all expressions and
103
///   - resolves all identifiers
104
///   - calculates resulting types (incl. coercion)
105
/// </summary>
106
public final class OoaResolveExpressionsVisitor extends OoaCompleteAstTraversalVisitor
107
{
108
	// we allow for free variable in expressions. collect them here.
109
	private final Stack<SymbolTable> m_freeVariables = new Stack<SymbolTable>();
110
	private Expression m_entryExpression = null;
111

  
112
	// helpers that replace the old expression in the AST by the new one.
113
	private void ReplaceExpression(IAst parent, Expression subElement, Expression newExpression)
114
	{
115
		switch (parent.nodeType())
116
		{
117
			case identifier:
118
				ReplaceExpressionInIdentifier((Identifier)parent, subElement, newExpression);
119
				break;
120
			case statement:
121
				ReplaceExpressionInStatement((Statement)parent, subElement, newExpression);
122
				break;
123
			default:
124
				throw new NotImplementedException();
125
		}
126
	}
127
	private void ReplaceExpressionInIdentifier(Identifier identifier, Expression subElement, Expression newExpression)
128
	{
129
		switch (identifier.kind())
130
		{
131
			case AttributeIdentifier:
132
				final AttributeIdentifier ident = (AttributeIdentifier)identifier;
133
				assert(ident.initializer() == subElement); // ref equ.
134
				ident.SetInitializer(newExpression);
135
				break;
136
			case Constant:
137
				final ConstantIdentifier aconst = (ConstantIdentifier)identifier;
138
				assert(aconst.Value() == subElement); // ref equ
139
				aconst.SetValue(newExpression);
140
				if (newExpression.kind() != ExpressionKind.Value)
141
					Error(aconst.Value(), String.format("%s not a constant!", aconst.tokenText()));
142
				break;
143
			default:
144
				throw new NotImplementedException();
145
		}
146
	}
147
	private void ReplaceExpressionInStatement(Statement statement, Expression subElement, Expression newExpression)
148
	{
149
		switch (statement.kind())
150
		{
151
			case GuardedCommand:
152
				final GuardedCommand gc = (GuardedCommand)statement;
153
				assert(gc.guard() == subElement); // ref eq
154
				gc.SetGuard(newExpression);
155
			break;
156
			case SeqBlock:
157
				final SeqBlock sqblock = (SeqBlock)statement;
158
				assert(sqblock.filter() == subElement); // ref eq
159
				sqblock.SetFilter(null);
160
				// we convert the filter to a guarded command...
161
				final SeqBlock implseq = new SeqBlock(sqblock.line(), sqblock.pos());
162
				implseq.SetStatements(sqblock.statements());
163
				final GuardedCommand implguard = new GuardedCommand(newExpression, implseq, sqblock.line(), sqblock.pos());
164
				sqblock.SetStatements(new LinkedList<Statement>());
165
				sqblock.AddStatement(implguard);
166
				break;
167
			case Assignment:
168
				final Assignment zw = (Assignment)statement;
169
				boolean found = false;
170
				if (zw.nondetExpression() == subElement) // ref eq
171
				{
172
					zw.SetNondetExpression(newExpression);
173
					found = true;
174
				}
175
				else
176
				{
177
					int cntr = 0;
178
					while (cntr < zw.places().size()) {
179
						if (zw.places().get(cntr) == subElement) { // ref eq
180
							zw.places().set(cntr, newExpression);
181
							found = true;
182
							break;
183
						}
184
						cntr ++;
185
					}
186
					if (!found) {
187
						cntr = 0;
188
						while (cntr < zw.values().size()) {
189
							if (zw.values().get(cntr) == subElement) { // ref eq.
190
								zw.values().set(cntr, newExpression);
191
								found = true;
192
								break;
193
							}
194
							cntr ++;
195
						}
196
					}
197
				}
198
				assert(found);
199
				break;
200
			case MethodCall:
201
				final Call call = (Call)statement;
202
				assert(call.callExpression() == subElement); // ref eq.
203
				call.SetCallExpression(newExpression);
204
				break;
205
			default:
206
				throw new NotImplementedException();
207
		}
208
	}
209

  
210
	// helper that returns null and adds an error message in the parserstate errorlist.
211
	private Expression Error(Expression expression, String p)
212
	{
213
		final ParserError error = new ParserError(m_ParserState.filename,
214
				expression.line(), expression.pos(), p);
215
		m_ParserState.AddErrorMessage(error);
216
		return null;
217
	}
218
	private void Info(Expression expression, String p)
219
	{
220
		final ParserMessage msg = new ParserMessage(m_ParserState.filename,
221
				expression.line(), expression.pos(), p);
222
		m_ParserState.AddMessage(msg);
223
	}
224
	// helper that adds a warning message to the output
225
	private void Warning(Identifier expression, String p)
226
	{
227
		final ParserWarning warning = new ParserWarning(m_ParserState.filename,
228
				expression.line(), expression.column(), p);
229
		m_ParserState.AddWarningMessage(warning);
230
	}
231
	private void Warning(Expression expression, String p)
232
	{
233
		final ParserWarning warning = new ParserWarning(m_ParserState.filename,
234
				expression.line(), expression.pos(), p);
235
		m_ParserState.AddWarningMessage(warning);
236
	}
237

  
238
	private final ArrayList<TupleConstructor> m_matcherList = new ArrayList<TupleConstructor>();
239

  
240
	///
241
	///   Resolve Expressions
242
	///
243

  
244
	private Expression ResolveExpression(TernaryOperator expression)
245
	{
246
		if (expression.kind() == ExpressionKind.conditional)
247
		{
248
			final Expression left = ResolveExpression(expression.left());
249
			Expression mid = ResolveExpression(expression.mid());
250
			Expression right = ResolveExpression(expression.right());
251

  
252
			if (left == null || mid == null || right == null)
253
				return null;
254

  
255
			if (left.type() == null || left.type().kind() != TypeKind.BoolType)
256
				return Error(expression, "Conditional: Condition not a bool");
257

  
258
			if (mid.type() == null || right.type() == null)
259
				return Error(expression, "Conditional: Then or Else branch has void-type");
260

  
261
			final UlyssesType acover = UlyssesType.CoverType(mid.type(), right.type());
262

  
263
			if (acover == null)
264
				return Error(expression, String.format(
265
					"Conditional: Then and Else branch must be of same type. (%s <> %s)",
266
					mid.type().toString(), right.type().toString()));
267

  
268
			if (!UlyssesType.TypeEqual(acover, mid.type()))
269
			{
270
				mid = new UnaryOperator(ExpressionKind.Cast, mid, mid.line(), mid.pos());
271
				mid.SetType(acover);
272
			}
273
			if (!UlyssesType.TypeEqual(acover, right.type()))
274
			{
275
				right = new UnaryOperator(ExpressionKind.Cast, right, right.line(), right.pos());
276
				right.SetType(acover);
277
			}
278

  
279

  
280
			expression.SetLeftChild(left);
281
			expression.SetMidChild(mid);
282
			expression.SetRightChild(right);
283
			expression.SetType(mid.type());
284
			return expression;
285
		}
286
		else if (expression.kind() == ExpressionKind.foldLR || expression.kind() == ExpressionKind.foldRL)
287
		{
288
			CallExpression leftcall = expression.left().kind() != ExpressionKind.Call
289
				? new CallExpression(expression.left(), new ArrayList<Expression>(), expression.line(),
290
					expression.pos(), expression.definingScope())
291
				: (CallExpression)expression.left();
292

  
293
			leftcall = (CallExpression)ResolveExpression(leftcall, true);
294
			if (leftcall == null)
295
				return null;
296

  
297
			final Expression afun = ResolveExpression(leftcall.child());
298
			leftcall.SetChild(afun);
299
			if (afun == null || afun.type() == null || afun.type().kind() != TypeKind.FunctionType)
300
				return Error(expression, "Fold/Map operation needs a method or named action as LHS");
301

  
302
			final FunctionType funType = (FunctionType)afun.type();
303
			if (funType.returnType() == null && expression.mid() != null)
304
				return Error(expression, "Fold operation needs a method with matching return type");
305
			if (funType.returnType() != null && expression.mid() == null)
306
				Warning(expression, "Map operation will discard result of function");
307

  
308
			final boolean isMap = expression.mid() == null;
309
			Expression mid = expression.mid();
310
			if (!isMap)
311
			{
312
				mid = ResolveExpression(mid);
313
				if ((funType.parameter().size() - leftcall.arguments().size()) != 2)
314
					return Error(expression, "Function used in fold operation needs 2 not-instantiated parameters");
315
			} else if ((funType.parameter().size() - leftcall.arguments().size()) != 1)
316
				return Error(expression, "Function used in map operation needs one not-instantiated parameter");
317

  
318
			final Expression right = ResolveExpression(expression.right());
319
			if (right == null || right.type() == null || right.type().kind() != TypeKind.ListType)
320
				return Error(expression, "Fold/Map operation needs list as RHS");
321

  
322
			if (!isMap)
323
			{
324
				final int nextToLast = funType.parameter().size() - 2;
325
				final UlyssesType initCover = UlyssesType.CoverType(funType.parameter().get(nextToLast), mid.type());
326
				if (initCover == null)
327
					return Error(expression, "Next to last parameter does not match initializer type in map operation.");
328
				if (!UlyssesType.TypeEqual(mid.type(), initCover))
329
					mid = new UnaryOperator(ExpressionKind.Cast, mid, mid.line(), mid.pos());
330
				mid.SetType(initCover);
331

  
332
				//List<Expression> args = new List<Expression> ();
333
				leftcall.arguments().add(new IdentifierExpression(new ParameterIdentifier("_result", initCover, null), 0, 0));
334
				leftcall.arguments().add(new IdentifierExpression(new ParameterIdentifier("_elem", funType.parameter().peekLast(), null), 0, 0));
335
				//leftcall.SetArguments(args);
336
			}
337
			// UlyssesType listCover = UlyssesType.CoverType(funType.parameter.Last.Value, ((ListType)right.type).innerType);
338
			// if (listCover == null)
339
			if (!UlyssesType.TypeEqual(funType.parameter().peekLast(), ((ListType)right.type()).innerType()))
340
				return Error(expression, "Last paramter does not match inner-type of list in fold/map operation");
341

  
342
			expression.SetLeftChild(leftcall);
343
			expression.SetMidChild(mid);
344
			expression.SetRightChild(right);
345
			if (!isMap)
346
				expression.SetType(funType.returnType());
347
			else
348
				expression.SetType(new NullType());
349
			return expression;
350
		} else
351
			throw new ArgumentException();
352
	}
353
	private Expression ResolveExpression(ForallQuantifier expression)
354
	{
355
		final Expression child = ResolveExpression(expression.child());
356
		if (child == null)
357
			return null;
358

  
359
		expression.SetType(new BoolType(null));
360
		expression.SetChild(child);
361
		return expression;
362
	}
363
	private Expression ResolveExpression(ExistsQuantifier expression)
364
	{
365
		final Expression child = ResolveExpression(expression.child());
366
		if (child == null)
367
			return null;
368

  
369
		expression.SetType(new BoolType(null));
370
		expression.SetChild(child);
371
		return expression;
372
	}
373
	private Expression ResolveExpression(ListConstructor expression)
374
	{
375
		UlyssesType type = null;
376
		ListType restype = null;
377
		Expression comprehension = null;
378
		if (expression.comprehension() != null)
379
		{
380
			comprehension = ResolveExpressionNewScope(expression.comprehension());
381

  
382
			if (comprehension == null)
383
				return null;
384

  
385
			if (comprehension.type() == null)
386
				return Error(expression, "List comprehension has void expression");
387

  
388
			if (comprehension.type().kind() != TypeKind.BoolType)
389
				return Error(expression, "List comprehension has to be bool-expression");
390

  
391
			expression.SetComprehension(comprehension);
392

  
393
			if (expression.elements().size() != 1)
394
				return Error(expression, "List comprehension expects one initializer expression");
395
		}
396

  
397
		final ArrayList<Expression> newitems = new ArrayList<Expression>();
398

  
399
		if (expression.elements().size() == 0 || expression.elements().get(0) == null || (
400
		        expression.elements().get(0).kind() == ExpressionKind.Value &&
401
		        expression.elements().get(0) instanceof ValueExpression<?> &&
402
		        ((ValueExpression<?>)expression.elements().get(0)).value() == null))
403
		{
404
			// empty list
405
			type = new NullType();
406
		}
407
		else
408
		{
409
			final ArrayList<Expression> tmpitems = new ArrayList<Expression>();
410
			for (final Expression item: expression.elements())
411
			{
412
				final Expression element = ResolveExpression(item);
413
				if (element == null)
414
					return null;
415
				if (element.type() == null)
416
					return Error(expression, "Void expression in list initializer");
417

  
418
				if (element.kind() == ExpressionKind.Value &&
419
				    element instanceof ValueExpression<?> &&
420
				    ((ValueExpression<?>)element).value() == null)
421
				{
422
					return Error(expression, "Not-In-List (nil) values not allowed in a list");
423
				}
424

  
425
				// calculate the type we're constructing
426
				if (type == null)
427
					type = element.type();
428

  
429
				type = UlyssesType.CoverType(type, element.type());
430
				if (type == null)
431
					return Error(expression, "List constructor needs matching types");
432

  
433
				tmpitems.add(element);
434
			}
435

  
436
			// now we have the resulting type - we still need to insert casts that might be necessary
437
			for (final Expression item: tmpitems)
438
			{
439
				if (!UlyssesType.TypeEqual(item.type(), type))
440
				{
441
					final Expression cast = new UnaryOperator(ExpressionKind.Cast, item, item.line(), item.pos());
442
					cast.SetType(type);
443
					newitems.add(cast);
444
				}
445
				else
446
					newitems.add(item);
447
			}
448
		}
449

  
450
		expression.SetElements(newitems);
451
		if (comprehension == null)
452
			restype = new ListType(type, newitems.size(), null);
453
		else
454
			restype = new ListType(type, -1, null); // we do not know anything about the bound
455

  
456
		expression.SetType(restype);
457
		return expression;
458
	}
459
	private Expression ResolveExpression(SetConstructor expression)
460
	{
461
		UlyssesType type = null;
462
		ListType restype = null;
463
		Expression comprehension = null;
464
		if (expression.comprehension() != null)
465
		{
466
			comprehension = ResolveExpressionNewScope(expression.comprehension());
467

  
468
			if (comprehension == null)
469
				return null;
470

  
471
			if (comprehension.type() == null)
472
				return Error(expression, "Set comprehension has void expression");
473

  
474
			if (comprehension.type().kind() != TypeKind.BoolType)
475
				return Error(expression, "Set comprehension has to be bool-expression");
476

  
477
			expression.SetComprehension(comprehension);
478

  
479
			if (expression.items().size() != 1)
480
				return Error(expression, "Set comprehension expects one initializer expression");
481
		}
482

  
483
		final ArrayList<Expression> newitems = new ArrayList<Expression>();
484
		for (final Expression item: expression.items())
485
		{
486
			final Expression element = ResolveExpression(item);
487
			if (element == null)
488
				return null;
489

  
490
			if (element.type() == null)
491
				return Error(expression, "Void expression in set initializer");
492

  
493
			if (type == null)
494
				type = element.type();
495
			type = UlyssesType.CoverType(type, element.type());
496
			if (type == null)
497
				return Error(expression, "Set initializer needs matching types");
498

  
499
			newitems.add(element);
500
		}
501
		expression.SetItems(newitems);
502
		restype = new ListType(type, newitems.size(), null);
503

  
504
		expression.SetType(restype);
505
		return expression;
506
	}
507
	private Expression ResolveExpression(MapConstructor expression)
508
	{
509
		UlyssesType domain = null;
510
		UlyssesType range = null;
511
		final ArrayList<MapConstructor.MapItem> newitems = new ArrayList<MapConstructor.MapItem>();
512

  
513
		for(final MapItem item: expression.items())
514
		{
515
			final Expression domexpr = ResolveExpression(item.key);
516
			if (domexpr == null)
517
				return null;
518

  
519
			if (domexpr.type() == null)
520
				return Error(expression, "Domain initializing expression void");
521

  
522
			if (domain == null)
523
				domain = domexpr.type();
524

  
525
			final Expression rangeexpr = ResolveExpression(item.value);
526
			if (rangeexpr == null)
527
				return null;
528

  
529
			if (rangeexpr.type() == null)
530
				return Error(expression, "Range initializing expression void");
531

  
532
			if (range == null)
533
				range = rangeexpr.type();
534

  
535
			domain = UlyssesType.CoverType(domain, domexpr.type());
536
			range = UlyssesType.CoverType(range, rangeexpr.type());
537
			if (domain == null)
538
				return Error(expression, "Types of domain expressions do not match");
539

  
540
			if (range == null)
541
				return Error(expression, "Types of range expressions do not match");
542

  
543
			newitems.add(new MapConstructor.MapItem(domexpr, rangeexpr));
544
		}
545

  
546
		expression.SetItems(newitems);
547
		final MapType resulttype = new MapType(domain, range, newitems.size(), null);
548
		expression.SetType(resulttype);
549
		return expression;
550
	}
551
	private Expression ResolveExpression(TupleConstructor expression)
552
	{
553
		final TupleType typeToConstruct = (TupleType)expression.tupleType().type();
554

  
555
		if (expression.values().size() != typeToConstruct.innerTypes().size())
556
			return Error(expression, String.format("Tuple constructor has wrong arity. (%s <> %s)",
557
				typeToConstruct.innerTypes().size(), expression.values().size()));
558

  
559
		//TupleType resulttype = new TupleType(null);
560
		final ArrayList<Expression> newvalexprs = new ArrayList<Expression>();
561

  
562
		final Iterator<UlyssesType> innerTargetType = typeToConstruct.innerTypes().iterator();
563
		int freeVarCount = 0;
564
		for (final Expression initexpr: expression.values())
565
		{
566
			final UlyssesType innerTargetTypeValue = innerTargetType.next();
567
			Expression newval = ResolveExpression(initexpr);
568
			if (newval == null)
569
				return null;
570
			if (newval.type() == null)
571
				return Error(expression, "Element has void type");
572

  
573
			if (newval.type().kind() == TypeKind.Any)
574
			{
575
				// free var - so set type.
576
				final AnyType freevar = (AnyType)newval.type();
577
				freevar.VariableIdentifier().SetType(innerTargetTypeValue);
578
				freevar.VariableIdentifier().SetInitialized(true);
579
				freeVarCount++;
580
			}
581
			else
582
			{
583
				final UlyssesType acover = UlyssesType.CoverType(innerTargetTypeValue, newval.type());
584
				if (acover == null || !UlyssesType.TypeEqualByKind(innerTargetTypeValue, acover))
585
					return Error(expression,
586
						String.format("Element in tuple constructor has non-matching type (%s <> %s)",
587
								innerTargetTypeValue.toString(), newval.type().toString()));
588

  
589
				if (!UlyssesType.TypeEqual(acover, newval.type()))
590
				{
591
					newval = new UnaryOperator(ExpressionKind.Cast, newval, newval.line(), newval.pos());
592
					newval.SetType(acover);
593
				}
594
				if (UlyssesType.FirstTypeLessRange(innerTargetTypeValue, acover)) {
595
					Warning(expression,
596
						String.format("Tuple constructor may over/underflow: %s := %s",
597
								innerTargetTypeValue.toString(), acover.toString()));
598
					newval = new UnaryOperator(ExpressionKind.Cast, newval, newval.line(), newval.pos());
599
					newval.SetType(innerTargetTypeValue);
600
				}
601
			}
602

  
603
			newvalexprs.add(newval);
604
			//resulttype.AddType(newval.type);
605
		}
606

  
607
		if (freeVarCount > 0)
608
		{
609
			if (freeVarCount != expression.values().size())
610
				return Error(expression, String.format("Tuple constructor must have 0 or #elems (%s) free variables", expression.values().size()));
611
			else
612
			{
613
				expression.SetIsMatcher(true); // mark this tuple constructor as matcher, since this is the only thing it does..
614
				m_matcherList.add(expression); // matcher has to be bound by one equality
615
			}
616
		}
617

  
618
		expression.SetTupleValues(newvalexprs);
619
		//expression.SetType(resulttype);
620
		expression.SetType(typeToConstruct); // the constructor always will create the correct type!
621
		return expression;
622
	}
623

  
624
	private Expression ResolveExpression(QValConstructor expression)
625
	{
626
		Expression basevalue = null;
627
		Expression rangevalue = null;
628

  
629
		basevalue = ResolveExpression(expression.value()[0]);
630
		if (basevalue == null || basevalue.kind() != ExpressionKind.Access
631
		    || basevalue.type() == null || basevalue.type().kind() != TypeKind.QrType)
632
			return Error(expression, "Landmark expected.");
633
		expression.SetType(basevalue.type());
634
		expression.SetValue(basevalue);
635

  
636
		if (expression.value().length == 2)
637
		{
638
			rangevalue = ResolveExpression(expression.value()[1]);
639
			if (rangevalue == null || rangevalue.kind() != ExpressionKind.Access
640
			    || rangevalue.type() == null || rangevalue.type().kind() != TypeKind.QrType)
641
				return Error(expression, "Landmark expected.");
642
			if (!UlyssesType.TypeEqual(basevalue.type(), rangevalue.type()))
643
				return Error(expression, String.format("Quantity spaces do not match: %s <> %s",
644
						basevalue.type().toString(),
645
						rangevalue.type().toString()));
646
			expression.AddRange(rangevalue);
647
		}
648
		return expression;
649
	}
650

  
651
	private Expression ResolveExpression(IdentifierExpression expression)
652
	{
653
		// nothing to do here, since we do not have any consts that may be
654
		// folded
655
		if ((expression.identifier().kind() == IdentifierKind.MethodIdentifier
656
		       || expression.identifier().kind() == IdentifierKind.NamedActionIdentifier)
657
		    && !m_entryExpression.callTargets().contains(expression.identifier()))
658
		{
659
			m_entryExpression.callTargets().add((FunctionIdentifier)expression.identifier());
660
		}
661

  
662
		return expression;
663
	}
664
	private Expression ResolveExpression(UnresolvedIdentifierExpression expression)
665
	{
666
		Identifier anid;
667
		//Identifier self = m_ParserState.Lookup("self");
668

  
669
		if (m_freeVariables.peek().Defined(expression.tokenText()))
670
			anid = m_freeVariables.peek().Get(expression.tokenText());
671
		else
672
			anid = m_ParserState.Lookup(expression.tokenText(), expression.scope());
673

  
674
		if (anid != null)
675
		{
676
			switch (anid.kind())
677
			{
678
			case TypeIdentifier:
679
				// only return a TypeExpression if this TypeIdentifier didn't come from a "self"
680
				if (anid instanceof SelfTypeIdentifier) {
681
					final IdentifierExpression result = new IdentifierExpression(anid, expression.line(), expression.pos());
682
					result.setIsSelf(true);
683
					return result;
684
				} else
685
					return new TypeExpression(anid.type(), expression.line(), expression.pos());
686

  
687
			case MethodIdentifier:
688
				m_entryExpression.callTargets().add((FunctionIdentifier)anid);
689
				final SelfTypeIdentifier selfid = (SelfTypeIdentifier)m_ParserState.Lookup("self", expression.scope());
690
				if ((selfid != null) && ((OoActionSystemType)(selfid).type()).symbols().Defined(anid))
691
				{
692
					// if it's a self access, add a self identifier (needed by cadp backend, e.g.)
693
					// self.<method> is handled in a separate method and does not call us here!! (hence this code is working)
694
					final IdentifierExpression aself = new IdentifierExpression(selfid, expression.line(), expression.pos());
695
					aself.setIsSelf(true);
696
					final AccessExpression localaccess = new AccessExpression(aself, new IdentifierExpression(anid, expression.line(), expression.pos()),
697
							expression.line(), expression.pos());
698
					ResolveExpression(localaccess);
699
					return localaccess;
700
				}
701
				else
702
				{
703
					return new IdentifierExpression(anid, expression.line(), expression.pos());
704
				}
705

  
706
			case NamedActionIdentifier:
707
				m_entryExpression.callTargets().add((FunctionIdentifier)anid);
708
				return new IdentifierExpression(anid, expression.line(), expression.pos());
709

  
710
			case Constant:
711
				if (((ConstantIdentifier)anid).Value() != null)
712
					return ((ConstantIdentifier)anid).Value().Clone();
713
				else
714
					return null;
715

  
716
			default:
717
				return new IdentifierExpression(anid, expression.line(), expression.pos());
718
			}
719
		}
720
		else
721
		{
722
			final ExpressionVariableIdentifier freeVar =
723
					new ExpressionVariableIdentifier(expression.tokenText(), expression.line(), expression.pos());
724
			freeVar.SetType(new AnyType(freeVar));
725
			m_freeVariables.peek().AddIdentifier(freeVar);
726

  
727
			// add a warning about free variables - do not change text without changing the text in ooaTypeCheckVisitor..
728
			Warning(freeVar, String.format("Free variable in expression: '%s'.", freeVar.tokenText()));
729

  
730
			return new IdentifierExpression(freeVar, expression.line(), expression.pos());
731
		}
732
	}
733
	private Expression ResolveExpression(TupleMapAccessExpression expression)
734
	{
735
		final Expression child = ResolveExpression(expression.child());
736
		if (child == null)
737
			return null;
738

  
739
		final Expression arg = ResolveExpression(expression.argument());
740
		if (arg == null)
741
			return null;
742

  
743

  
744
		assert(child.type() != null);
745

  
746
		if ((child.kind() != ExpressionKind.Type) && (child.type().kind() == TypeKind.TupleType))
747
		{
748
			if ((arg.kind() != ExpressionKind.Value)
749
			    || (((LeafExpression)arg).valueType() != LeafTypeEnum.integer))
750
			{
751
				return Error(expression, "Argument to tuple access must be constant integer value!");
752
			}
753
			final TupleType aTuple = (TupleType)child.type();
754
			@SuppressWarnings("unchecked")
755
			final
756
			ValueExpression<Integer> aval = (ValueExpression<Integer>)arg;
757
			if ((aval.value() < 0) || (aval.value() >= aTuple.innerTypes().size()))
758
			{
759
				return Error(expression, "Argument to tuple access has to be in range 0..#elems-1");
760
			}
761
//			LinkedListNode<UlyssesType> anode = aTuple.innerTypes().First;
762
//			int target = aval.value();
763
//			while (target > 0)
764
//			{
765
//				target--;
766
//				anode = anode.Next;
767
//			}
768
//			expression.SetType(anode.Value);
769
			expression.SetType(aTuple.innerTypes().get(aval.value()));
770
		}
771
		else if ((child.kind() != ExpressionKind.Type) && (child.type().kind() == TypeKind.MapType))
772
		{
773
			final MapType amap = (MapType)child.type();
774
			expression.SetType(amap.toType());
775
		}
776
		else if ((child.kind() != ExpressionKind.Type) && (child.type().kind() == TypeKind.ListType))
777
		{
778
			// we allow element access of lists via list[i]
779
			final ListType alist = (ListType)child.type();
780
			expression.SetType(alist.innerType());
781
		}
782
		else
783
		{
784
			return Error(expression, "Not a list, tuple, or map instance");
785
		}
786
		expression.SetArgument(arg);
787
		expression.SetChild(child);
788
		return expression;
789
	}
790
	private Expression ResolveExpression(CallExpression expression)
791
	{
792
		return ResolveExpression(expression, false);
793
	}
794
	private Expression ResolveExpression(CallExpression expression, boolean allowFewerParameters)
795
	{
796
		// calc type of child
797
		final Expression child = ResolveExpression(expression.child());
798
		if (child == null)
799
			return null;
800

  
801
		assert(child.type() != null);
802

  
803
		expression.SetChild(child);
804

  
805
		if (child.type().kind() != TypeKind.FunctionType)
806
		{
807
			return Error(expression, "No function to call!");
808
		}
809

  
810

  
811
		final FunctionType funtype = (FunctionType)child.type();
812

  
813
//		// check whether call of named action is allowed
814
//		if (funtype.functionType() != FunctionTypeEnum.Method)
815
//		{
816
//			// see if call is allowed: must not be called from within a named action
817
//			IScope callingScope = expression.scope();
818
//			while (callingScope != null)
819
//			{
820
//				if (callingScope instanceof NamedActionIdentifier || callingScope instanceof MethodIdentifier)
821
//					return Error(expression, "Call of named Action only allowed in do-od block!");
822
//				callingScope = callingScope.GetParentScope();
823
//			}
824
//		}
825

  
826
		// check arguments
827
		final int argsSpec = funtype.parameter().size();
828
		final int argsHave = expression.arguments().size();
829
		if (argsHave < argsSpec && !allowFewerParameters)
830
		{
831
			return Error(expression, "Too few parameters in function call");
832
		}
833
		if (argsHave > argsSpec)
834
		{
835
			return Error(expression, "Too much parameters in function call");
836
		}
837

  
838
		final ArrayList<Expression> newargs = new ArrayList<Expression>();
839
		final Iterator<UlyssesType> demandedArgType = funtype.parameter().iterator();
840
		for (final Expression arg: expression.arguments())
841
		{
842
			final UlyssesType demandedArgTypeValue = demandedArgType.next();
843
			Expression newarg = ResolveExpression(arg);
844
			if (newarg == null)
845
				return null;
846

  
847
			if (newarg.GetUninitializedFreeVariables().size() > 0)
848
				Error(arg, String.format("Undefined variable '%s'",
849
					newarg.GetUninitializedFreeVariables().get(0).tokenText()));
850

  
851
			final Expression constantvalue = newarg.kind() == ExpressionKind.Value ? newarg : null;
852

  
853
			final UlyssesType acover = UlyssesType.CoverType(newarg.type(), demandedArgTypeValue);
854
			if (acover == null || !UlyssesType.TypeEqualByKind(demandedArgTypeValue, acover))
855
				return Error(arg, String.format("Argument type does not match; expected: %s delivered: %s",
856
						demandedArgTypeValue.toString(), newarg.type().toString()));
857

  
858
			newarg = UnaryOperator.TryCoerceUp(newarg, acover);
859

  
860
			if (UlyssesType.FirstTypeLessRange(demandedArgTypeValue, acover))
861
			{
862
				if (constantvalue == null)
863
				{
864
					Warning(arg, String.format("Call parameter may over/underflow: %s := %s",
865
							demandedArgTypeValue.toString(), acover.toString()));
866
					final UnaryOperator cast = new UnaryOperator(ExpressionKind.Cast, newarg, newarg.line(), newarg.pos());
867
					cast.SetType(demandedArgTypeValue);
868
					newarg = cast;
869
				}
870
				else
871
				{
872
					Error(arg, String.format("Call parameter out of range (%s  := %s)",
873
							demandedArgTypeValue.toString(), constantvalue.toString()));
874
				}
875
			}
876

  
877
			newargs.add(newarg);
878
		}
879
		expression.SetArguments(newargs);
880

  
881
		if (funtype.returnType() != null)
882
			expression.SetType(funtype.returnType());
883
		return expression;
884
	}
885
	private Expression ResolveExpression(AccessExpression expression)
886
	{
887
		Expression lhs = ResolveExpression(expression.left());
888
		if (lhs == null)
889
			return null;
890
		if (!(expression.right() instanceof UnresolvedIdentifierExpression))
891
		{
892
			expression.SetRightChild(ResolveExpression(expression.right()));
893
			expression.SetType(expression.right().type());
894
			return expression;
895
		}
896

  
897
		final boolean selfAccess = (lhs.kind() == ExpressionKind.Identifier) && ((IdentifierExpression)lhs).isSelf();
898
		final boolean staticAccess = lhs.kind() == ExpressionKind.Type;
899
		final UnresolvedIdentifierExpression access = (UnresolvedIdentifierExpression)expression.right();
900
		// atype could be null...
901
		UlyssesType atype = lhs.type();
902
		if ((lhs.kind() == ExpressionKind.Call) && (atype == null))
903
		{
904
			return Error(access, "Can not access return type of void-function");
905
		}
906
		else if (atype == null)
907
		{
908
			return Error(access, "Can not access member of a void type");
909
		}
910

  
911
		// if we did not apply a call expression to a function
912
		if (atype.kind() == TypeKind.FunctionType)
913
		{
914
			// we can access the return val...
915
			final FunctionType fun = (FunctionType)atype;
916

  
917
			// check arity
918
			if (fun.parameter().size() > 0)
919
				return Error(access, "Implicit function call not possible: Too few parameters.");
920

  
921
			// check return type
922
			if (fun.returnType() == null)
923
				return Error(access, "Can not access return type of void-function!");
924

  
925
			// call ok
926
			atype = fun.returnType();
927
			// but add callExpression
928
			lhs = new CallExpression(lhs, null, lhs.line(), lhs.pos(), null); // we do not know the scope
929
			lhs.SetType(atype);
930
		}
931

  
932
		// update left child
933
		expression.SetLeftChild(lhs);
934

  
935

  
936
		switch (atype.kind())
937
		{
938
		case OoActionSystemType:
939
			final Identifier anid = ((OoActionSystemType)atype).ResolveIdentifier(access.tokenText());
940
			if (anid != null)
941
			{
942
				if (anid.kind() == IdentifierKind.MethodIdentifier && !m_entryExpression.callTargets().contains(anid))
943
					m_entryExpression.callTargets().add((FunctionIdentifier)anid);
944

  
945
				if (staticAccess)
946
				{
947
					if ((anid.kind() == IdentifierKind.AttributeIdentifier) &&
948
							(((AttributeIdentifier)anid).isStatic()))
949
					{
950
						final IdentifierExpression newrhs = new IdentifierExpression(anid, access.line(), access.pos());
951
						expression.SetRightChild(newrhs);
952
					}
953
					else
954
						return Error(access, "Can not access non-static member of an action system");
955
				}
956
				else
957
				{
958
					if (anid.kind() != IdentifierKind.MethodIdentifier && !selfAccess)
959
						return Error(access, "Can only access methods of action system objects");
960
					else
961
					{
962
						final IdentifierExpression newrhs = new IdentifierExpression(anid, access.line(), access.pos());
963
						expression.SetRightChild(newrhs);
964
					}
965
				}
966
			}
967
			else
968
				return Error(access, String.format("%s no member of %s",
969
						access.tokenText(), ((OoActionSystemType)atype).identifier().tokenText()));
970
			break;
971
		case EnumeratedType:
972
			final EnumType anEnum = (EnumType)atype;
973
			if (!staticAccess)
974
			{
975
				return Error(access, "Enum values can only be accessed statically.");
976
			}
977
			if (anEnum.symbolTable().Defined(access.tokenText()))
978
			{
979
				final Identifier enumid = anEnum.symbolTable().Get(access.tokenText());
980
				final IdentifierExpression newrhs = new IdentifierExpression(enumid, access.line(), access.pos());
981
				expression.SetRightChild(newrhs);
982
			}
983
			else
984
				return Error(access, String.format("%s not contained in enum %s",
985
						access.tokenText(), anEnum.identifier().tokenText()));
986
			break;
987
		case QrType:
988
			final QrType aQualitativeType = (QrType)atype;
989
			if (!staticAccess)
990
			{
991
				return Error(access, "QSpace values can only be accessed statically.");
992
			}
993
			if (aQualitativeType.symbolTable().Defined(access.tokenText()))
994
			{
995
				final Identifier landmark = aQualitativeType.symbolTable().Get(access.tokenText());
996
				final IdentifierExpression newrhs = new IdentifierExpression(landmark, access.line(), access.pos());
997
				expression.SetRightChild(newrhs);
998
			}
999
			else
1000
				return Error(access, String.format("%s not contained in qspace %s",
1001
						access.tokenText(), aQualitativeType.identifier().tokenText()));
1002
			break;
1003
		default:
1004
			/*error, we can not access an element with '.' in any other type*/
1005
			return Error(expression, "Expected: System, Enum, Func, or QR type");
1006
		}
1007

  
1008
		expression.SetType(expression.right().type());
1009
		return expression;
1010
	}
1011
	private Expression ResolveExpression(UnaryOperator expression)
1012
	{
1013
		final Expression child = ResolveExpression(expression.child());
1014
		// if there was some error, then exit
1015
		if (child == null)
1016
			return null;
1017

  
1018
		if (child.type() == null)
1019
			return Error(expression, "Can not apply unary operator to void-expression");
1020

  
1021

  
1022
		switch (expression.kind())
1023
		{
1024
		case Primed:
1025
			expression.SetType(child.type());
1026
			break;
1027

  
1028
			/*map unary*/
1029
		case dom:           // map A to B -> list of A
1030
			if (child.type().kind() != TypeKind.MapType)
1031
				return Error(expression, "Domain operator only applicable to map types.");
1032
			MapType amap = (MapType)child.type();
1033
			ListType list = new ListType(amap.fromType(), amap.maxNumberOfElements(), null);
1034
			expression.SetType(list);
1035
			break;
1036
		case range:         // map A to B -> list of B
1037
			if (child.type().kind() != TypeKind.MapType)
1038
				return Error(expression, "Range operator only applicable to map types.");
1039
			amap = (MapType)child.type();
1040
			list = new ListType(amap.toType(), amap.maxNumberOfElements(), null);
1041
			expression.SetType(list);
1042
			break;
1043
		case merge:         // list of map A to B -> map A to B
1044
			if ((child.type().kind() == TypeKind.ListType) &&
1045
					(((ListType)child.type()).innerType().kind() == TypeKind.MapType))
1046
			{
1047
				expression.SetType(((ListType)child.type()).innerType());
1048
				break;
1049
			}
1050
			else
1051
				return Error(expression, "Merge operator only applicable to a list of maps");
1052
			/*set/list unary*/
1053
		case card:       // list of A -> int (does not respect dupes, i.e. dupes do not count)
1054
			if (child.type().kind() != TypeKind.ListType)
1055
				return Error(expression, "Cardinality operator only applicable to list types.");
1056
			expression.SetType(new IntType(0, ((ListType)child.type()).maxNumberOfElements(), null));
1057
			break;
1058
		case dconc:      // list of list of A -> list of A
1059
			if ((child.type().kind() == TypeKind.ListType)
1060
					&& (((ListType)child.type()).innerType().kind() == TypeKind.ListType))
1061
			{
1062
				list = (ListType)child.type();
1063
				final ListType innerlist = (ListType)list.innerType();
1064
				final int maxnumber = innerlist.maxNumberOfElements() * list.maxNumberOfElements();
1065
				expression.SetType(new ListType(innerlist.innerType(), maxnumber, null));
1066
				break;
1067
			}
1068
			else
1069
				return Error(expression, "Distributed Concatenation operator only applicable to list of lists");
1070
		case dinter:     // list of list of A -> list of A (intersection, does not respect dupes)
1071
			if ((child.type().kind() == TypeKind.ListType)
1072
					&& (((ListType)child.type()).innerType().kind() == TypeKind.ListType))
1073
			{
1074
				list = (ListType)child.type();
1075
				final ListType innerlist = (ListType)list.innerType();
1076
				final int maxnumber = innerlist.maxNumberOfElements();
1077
				expression.SetType(new ListType(innerlist.innerType(), maxnumber, null));
1078
				break;
1079
			}
1080
			else
1081
				return Error(expression, "Distributed Intersection operator only applicable to list of lists");
1082
		case dunion:     // list of list of A -> list of A (union, does not respect dupes)
1083
			if ((child.type().kind() == TypeKind.ListType)
1084
					&& (((ListType)child.type()).innerType().kind() == TypeKind.ListType))
1085
			{
1086
				list = (ListType)child.type();
1087
				final ListType innerlist = (ListType)list.innerType();
1088
				// better upper limit?!
1089
						final int maxnumber = innerlist.maxNumberOfElements() * list.maxNumberOfElements();
1090
						expression.SetType(new ListType(innerlist.innerType(), maxnumber, null));
1091
						break;
1092
			}
1093
			else
1094
				return Error(expression, "Distributed Union operator only applicable to list of lists");
1095
		case elems:      // list of A -> list of A (does not respect dupes)
1096
			if (child.type().kind() != TypeKind.ListType)
1097
				return Error(expression, "Element operator only applicable to list");
1098
			expression.SetType(child.type());
1099
			break;
1100
		case head:       // list of A -> A
1101
			if (child.type().kind() != TypeKind.ListType)
1102
				return Error(expression, "Head operator only applicable to list");
1103
			expression.SetType(((ListType)child.type()).innerType());
1104
			break;
1105
		case inds:       // list of A -> list of int
1106
			if (child.type().kind() != TypeKind.ListType)
1107
				return Error(expression, "Indices operator only applicable to list");
1108
			list = (ListType)child.type();
1109
			final IntType inner = new IntType(0, list.maxNumberOfElements(), null);
1110
			expression.SetType(new ListType(inner, list.maxNumberOfElements(), null));
1111
			break;
1112
		case len:        // list of A -> int (dupes count)
1113
			if (child.type().kind() != TypeKind.ListType)
1114
				return Error(expression, "Length operator only applicable to list");
1115
			list = (ListType)child.type();
1116
			expression.SetType(new IntType(0, list.maxNumberOfElements(), null));
1117
			break;
1118
		case tail:       // list of A -> list of A
1119
			if (child.type().kind() != TypeKind.ListType)
1120
				return Error(expression, "Tail operator only applicable to list");
1121
			list = (ListType)child.type();
1122
			if (list.maxNumberOfElements() == 0)
1123
				return Error(expression, "Tail operator only applicable to list of length > 0");
1124
			final int newmaxelems = list.maxNumberOfElements() - 1;
1125
			if (newmaxelems == 0)
1126
				Warning(expression, "Tail operator returns empty list.");
1127
			// set the return type null when list is empty?
1128
			expression.SetType(new ListType(list.innerType(), newmaxelems, null));
1129
			break;
1130
			/*unary numberic*/
1131
		case unminus:
1132
			if (!child.type().IsNumeric())
1133
				return Error(expression, "Unary minus only applicable to numeric types");
1134
			expression.SetType(Expression.ArithmeticCover(child.type(), null, expression.kind()));
1135
			break;
1136
		case unplus:
1137
			if (!child.type().IsNumeric())
1138
				return Error(expression, "Unary plus only applicable to numeric types");
1139
			expression.SetType(child.type());
1140
			break;
1141
		case abs:
1142
			if (!child.type().IsNumeric())
1143
				return Error(expression, "Abs only applicable to numeric types");
1144
			expression.SetType(child.type());
1145
			break;
1146
		case not:
1147
			if (/*!IsNumeric(child.type) && */
1148
					(child.type().kind() != TypeKind.BoolType))
1149
				return Error(expression, "Not only applicable to bool types");
1150
			expression.SetType(child.type());
1151
			break;
1152
			/*unary quantors*/
1153
		case forall:
1154
			expression.SetType(new BoolType(null));
1155
			break;
1156
		case exists:
1157
			expression.SetType(new BoolType(null));
1158
			break;
1159
		default:
1160
			throw new NotImplementedException();
1161
		}
1162

  
1163
		expression.SetChild(child);
1164
		return expression;
1165
	}
1166
	@SuppressWarnings("unchecked")
1167
	private Expression ResolveExpression(BinaryOperator expression)
1168
	{
1169
		Expression lhs = ResolveExpression(expression.left());
1170
		Expression rhs = ResolveExpression(expression.right());
1171

  
1172

  
1173
		// if there was some error, then exit
1174
		if ((lhs == null) || (rhs == null))
1175
			return null;
1176

  
1177
		final UlyssesType lt = lhs.type();
1178
		final UlyssesType rt = rhs.type();
1179

  
1180
		if ((lt == null) || (rt == null))
1181
			return Error(expression, "Binary operator not applicable to void-type subexpression.");
1182

  
1183

  
1184
		switch (expression.kind())
1185
		{
1186
		/*map operators*/
1187
		case domresby:   // list of A * map A to B -> map A to B
1188
		case domresto:   // list of A * map A to B -> map A to B
1189
			if (lt.kind() != TypeKind.ListType)
1190
				return Error(expression, "Domain restriction operator expects list on LHS");
1191
			if (rt.kind() != TypeKind.MapType)
1192
				return Error(expression, "Domain restriction operator expects map on RHS");
1193
			ListType domlist = (ListType)lt;
1194
			MapType domMap = (MapType)rt;
1195
			if (!UlyssesType.TypeEqual(domlist.innerType(), domMap.fromType()))
1196
				return Error(expression, "Inner type of list and domain-type of map do not match");
1197
			// since this is a restriction, maxnumofelems is ok
1198
			expression.SetType(domMap);
1199
			break;
1200
		case rngresby:   // map A to B * list of B -> map A to B
1201
		case rngresto:   // map A to B * list of B -> map A to B
1202
			if (lt.kind() != TypeKind.MapType)
1203
				return Error(expression, "Range restriction operator expects map on LHS");
1204
			if (rt.kind() != TypeKind.ListType)
1205
				return Error(expression, "Rangle restriction operator expects list on RHS");
1206
			final ListType rangelist = (ListType)rt;
1207
			domMap = (MapType)lt;
1208
			if (!UlyssesType.TypeEqual(rangelist.innerType(), domMap.fromType()))
1209
				return Error(expression, "Inner type of list and rangle-type of map do not match");
1210
			// since this is a restriction, maxnumofelems is ok
1211
			expression.SetType(domMap);
1212
			break;
1213
		case munion:     // map A to B * map A to B -> map A to B
1214
			if (lt.kind() != TypeKind.MapType ||
1215
			rt.kind() != TypeKind.MapType)
1216
				return Error(expression, "Map union expects maps on LHS and RHS");
1217
			domMap = (MapType)lt;
1218
			MapType rngMap = (MapType)rt;
1219
			if (!UlyssesType.TypeEqual(domMap.fromType(), rngMap.fromType()) ||
1220
					!UlyssesType.TypeEqual(domMap.toType(), rngMap.toType()))
1221
				return Error(expression, "Domain and Range types of maps must be equal");
1222
			// union may change maximum number of elements..
1223
			final MapType resMap = new MapType(domMap.fromType(), domMap.toType(),
1224
					domMap.maxNumberOfElements() + rngMap.maxNumberOfElements(), null);
1225
			expression.SetType(resMap);
1226
			break;
1227
			/*set/list binary*/
1228
		case conc:       // list of A * list of A -> list of A
1229
			if (lt.kind() != TypeKind.ListType ||
1230
			rt.kind() != TypeKind.ListType)
1231
				return Error(expression, "List concatenation expects two lists.");
1232
			ListType la = (ListType)lt;
1233
			ListType lb = (ListType)rt;
1234

  
1235
			if (lb.innerType().kind() == TypeKind.Null || lb.maxNumberOfElements() == 0)
1236
				return lhs;
1237
			if (la.innerType().kind() == TypeKind.Null || la.maxNumberOfElements() == 0)
1238
				return rhs;
1239
			if (!UlyssesType.TypeEqual(la.innerType(), lb.innerType()))
1240
				return Error(expression, String.format("Set/List concatenation expects two lists of same type. (%s <> %s)", la.toString(), lb.toString()));
1241
			ListType resultList = new ListType(la.innerType(),
1242
					la.maxNumberOfElements() + lb.maxNumberOfElements(), null);
1243
			expression.SetType(resultList);
1244
			break;
1245
		case diff:       // list of A * list of A -> list of A (does not respect dupes)
1246
			if (lt.kind() != TypeKind.ListType ||
1247
			rt.kind() != TypeKind.ListType)
1248
				return Error(expression, "Set difference expects two lists.");
1249
			la = (ListType)lt;
1250
			lb = (ListType)rt;
1251
			if (!UlyssesType.TypeEqual(la.innerType(), lb.innerType()))
1252
				return Error(expression, "Set difference expects two lists of same type.");
1253
			expression.SetType(la);
1254
			break;
1255
		case inter:      // list of A * list of A -> list of A (does not respect dupes)
1256
			if (lt.kind() != TypeKind.ListType ||
1257
			rt.kind() != TypeKind.ListType)
1258
				return Error(expression, "Set intersection expects two lists.");
1259
			la = (ListType)lt;
1260
			lb = (ListType)rt;
1261
			if (!UlyssesType.TypeEqual(la.innerType(), lb.innerType()))
1262
				return Error(expression, "Set intersection expects two lists of same type.");
1263
			expression.SetType(la.maxNumberOfElements() > lb.maxNumberOfElements() ? la : lb);
1264
			break;
1265
		case elemin:     // A * list of A -> bool
1266
		case notelemin:  // A * list of A -> bool
1267
			if (rt.kind() != TypeKind.ListType)
1268
				return Error(expression, "Element (not) in operator expects list-type as RHS.");
1269
			lb = (ListType)rt;
1270
			if (lhs.kind() == ExpressionKind.Value)
1271
				lhs = UnaryOperator.TryCoerceUp(lhs, lb.innerType());
1272
			final UlyssesType leftType = lhs.type();
1273
			if (!UlyssesType.TypeEqual(leftType, lb.innerType()))
1274
				return Error(expression, String.format("List and element must be of same type: %s in %s",
1275
						lt == null ? "<null>" : lt.toString(), lb ==null || lb.innerType() == null ? "<null>" : lb.innerType().toString()));
1276
			expression.SetType(new BoolType(null));
1277
			break;
1278
		case subset:     // list of A * list of A -> bool (does not respect dupes)
1279
			if (lt.kind() != TypeKind.ListType ||
1280
			rt.kind() != TypeKind.ListType)
1281
				return Error(expression, "Subset operation expects two lists.");
1282
			la = (ListType)lt;
1283
			lb = (ListType)rt;
1284
			if (!UlyssesType.TypeEqual(la.innerType(), lb.innerType()))
1285
				return Error(expression, "Subset operation expects two lists of same type.");
1286
			expression.SetType(new BoolType(null));
1287
			break;
1288
		case union:      // list of A * list of A -> list of A (does not respect dupes)
1289
			if (lt.kind() != TypeKind.ListType ||
1290
			rt.kind() != TypeKind.ListType)
1291
				return Error(expression, "Set union expects two lists.");
1292
			la = (ListType)lt;
1293
			lb = (ListType)rt;
1294

  
1295
			if (la.innerType().kind() == TypeKind.Null || la.maxNumberOfElements() == 0)
1296
				return rhs;
1297
			if (lb.innerType().kind() == TypeKind.Null || lb.maxNumberOfElements() == 0)
1298
				return lhs;
1299

  
1300
			if (!UlyssesType.TypeEqual(la.innerType(), lb.innerType()))
1301
				return Error(expression, "Set union expects two lists of same type.");
1302
			resultList = new ListType(la.innerType(),
1303
					la.maxNumberOfElements() + lb.maxNumberOfElements(), null);
1304
			expression.SetType(resultList);
1305
			break;
1306

  
1307
			/*numeric binary*/
1308
		case pow:
1309
			if (!lt.IsNumeric() || !rt.IsNumeric())
1310
				return Error(expression, "Operator expects LHS and RHS to be numeric");
1311
			if (lt.kind() == TypeKind.IntType && rt.kind() == TypeKind.IntType)
1312
				expression.SetType(lt);
1313
			else
1314
				if (lt.kind() == TypeKind.FloatType)
1315
					expression.SetType(lt);
1316
				else
1317
				{
1318
					final IntType anint = (IntType)lt;
1319
					expression.SetType(new FloatType(anint.rangeLow(), anint.rangeHigh(),
1320
							FloatType.defaultPrecision(), null));
1321
				}
1322
			break;
1323

  
1324
		case idiv:
1325
		case mod:
1326
			if (rt.kind() != TypeKind.IntType || lt.kind() != TypeKind.IntType)
1327
				return Error(expression, "Operator expects LHS and RHS to be integer");
1328
			expression.SetType(Expression.ArithmeticCover(lt, rt, expression.kind()));
1329
			break;
1330
		case div:
1331
			if (!rt.IsNumeric() || !lt.IsNumeric())
1332
				return Error(expression, "Operator expects LHS and RHS to be numeric");
1333
			if (lhs.type() instanceof ValuedEnumType)
1334
				lhs = UnaryOperator.TryCoerceUp(lhs, ((ValuedEnumType)lhs.type()).getIntType());
1335
			if (rhs.type() instanceof ValuedEnumType)
1336
				rhs = UnaryOperator.TryCoerceUp(rhs, ((ValuedEnumType)rhs.type()).getIntType());
1337
			UlyssesType cover = Expression.ArithmeticCover(lt, rt, expression.kind());
1338
			expression.SetType(cover);
1339
			break;
1340
		case minus:
1341
			if (!rt.IsNumeric() || !lt.IsNumeric())
1342
				return Error(expression, "Operator expects LHS and RHS to be numeric");
1343
			if (lhs.type() instanceof ValuedEnumType)
1344
				lhs = UnaryOperator.TryCoerceUp(lhs, ((ValuedEnumType)lhs.type()).getIntType());
1345
			if (rhs.type() instanceof ValuedEnumType)
1346
				rhs = UnaryOperator.TryCoerceUp(rhs, ((ValuedEnumType)rhs.type()).getIntType());
1347
			cover = Expression.ArithmeticCover(lt, rt, expression.kind());
1348
			expression.SetType(cover);
1349
			break;
1350
		case prod:
1351
			if (!rt.IsNumeric() || !lt.IsNumeric())
1352
				return Error(expression, "Operator expects LHS and RHS to be numeric");
1353
			if (lhs.type() instanceof ValuedEnumType)
1354
				lhs = UnaryOperator.TryCoerceUp(lhs, ((ValuedEnumType)lhs.type()).getIntType());
1355
			if (rhs.type() instanceof ValuedEnumType)
1356
				rhs = UnaryOperator.TryCoerceUp(rhs, ((ValuedEnumType)rhs.type()).getIntType());
1357
			cover = Expression.ArithmeticCover(lt, rt, expression.kind());
1358
			expression.SetType(cover);
1359
			break;
1360
		case sum:
1361
			if (!rt.IsNumeric() || !lt.IsNumeric())
1362
				return Error(expression, "Operator expects LHS and RHS to be numeric");
1363
			if (lhs.type() instanceof ValuedEnumType)
1364
				lhs = UnaryOperator.TryCoerceUp(lhs, ((ValuedEnumType)lhs.type()).getIntType());
1365
			if (rhs.type() instanceof ValuedEnumType)
1366
				rhs = UnaryOperator.TryCoerceUp(rhs, ((ValuedEnumType)rhs.type()).getIntType());
1367
			cover = Expression.ArithmeticCover(lt, rt, expression.kind());
1368
			expression.SetType(cover);
1369
			break;
1370
		case greater:
1371
		case greaterequal:
1372
		case less:
1373
		case lessequal:
1374
			if (!((rt.IsNumeric() && lt.IsNumeric()) || (rt.IsQualitative() && lt.IsQualitative())))
1375
				return Error(expression, "Operator expects LHS and RHS to be numeric or qualitative");
1376
			cover = UlyssesType.CoverType(lt, rt);
1377
			if (cover != null)
1378
			{
1379
				lhs = UnaryOperator.TryCoerceUp(lhs, cover);
1380
				rhs = UnaryOperator.TryCoerceUp(rhs, cover);
1381
				expression.SetType(new BoolType(null));
1382
			}
1383
			else
1384
				return Error(expression, String.format("Operator expects LHS and RHS to be of same type (%s <> %s)", lhs.type().toString(), rhs.type().toString()));
1385
			break;
1386
			/*bool binary*/
1387
		case and:
1388
			if (rt.kind() != TypeKind.BoolType || lt.kind() != TypeKind.BoolType)
1389
				return Error(expression, "Operator expects LHS and RHS of bool.");
1390

  
1391
			expression.SetType(rt);
1392
			// little bit of optimization..
1393
			if (rhs.kind() == ExpressionKind.Value
1394
					&& ((ValueExpression<Boolean>)rhs).value() == false)
1395
				return rhs;
1396
			else if (lhs.kind() == ExpressionKind.Value
1397
					&& ((ValueExpression<Boolean>)lhs).value() == false)
1398
				return lhs;
1399

  
1400
			// if both are true, then this will be taken care of in constant folding.
1401
			break;
1402
		case biimplies:
1403
			if (rt.kind() != TypeKind.BoolType || lt.kind() != TypeKind.BoolType)
1404
				return Error(expression, "Operator expects LHS and RHS of bool.");
1405
			expression.SetType(rt);
1406
			break;
1407
		case implies:
1408
			if (rt.kind() != TypeKind.BoolType || lt.kind() != TypeKind.BoolType)
1409
				return Error(expression, "Operator expects LHS and RHS of bool.");
1410
			expression.SetType(rt);
1411

  
1412
			// ex falso...
1413
			if (lhs.kind() == ExpressionKind.Value
1414
					&& ((ValueExpression<Boolean>)lhs).value() == false)
1415
			{
1416
				final Expression shortcut = new ValueExpression<Boolean>(true, expression.line(), expression.pos(), Boolean.class);
1417
				shortcut.SetType(lt);
1418
				return shortcut;
1419
			}
1420

  
1421
			break;
1422
		case or:
1423
			if (rt.kind() != TypeKind.BoolType || lt.kind() != TypeKind.BoolType)
1424
				return Error(expression, "Operator expects LHS and RHS of bool.");
1425
			expression.SetType(rt);
1426

  
1427
			if (rhs.kind() == ExpressionKind.Value
1428
					&& ((ValueExpression<Boolean>)rhs).value() == true)
1429
				return rhs;
1430
			else if (lhs.kind() == ExpressionKind.Value
1431
					&& ((ValueExpression<Boolean>)lhs).value() == true)
1432
				return lhs;
1433
			break;
1434
			/*other binary*/
1435
		case equal:
1436
		case notequal:
1437
			cover = UlyssesType.CoverType(lt, rt);
1438
			if (cover != null)
1439
			{
1440
				/* see whether we have a tuple-matcher on one side.. */
1441
				if (expression.kind() == ExpressionKind.equal)
1442
				{
1443
					if (lhs.kind() == ExpressionKind.TupleConstr &&
1444
							((TupleConstructor)lhs).isMatcher())
1445
					{
1446
						if (rhs.kind() == ExpressionKind.TupleConstr &&
1447
								((TupleConstructor)rhs).isMatcher())
1448
							return Error(expression, "Free variables on both sides of the equality sign in tuple constructors.");
1449
						m_matcherList.remove(lhs);
1450
					}
1451
					else if (rhs.kind() == ExpressionKind.TupleConstr &&
1452
							((TupleConstructor)rhs).isMatcher())
1453
					{
1454
						if (lhs.kind() == ExpressionKind.TupleConstr &&
1455
								((TupleConstructor)lhs).isMatcher())
1456
							return Error(expression, "Free variables on both sides of the equality sign in tuple constructors.");
1457
						m_matcherList.remove(rhs);
1458
					}
1459
				}
1460

  
1461
				lhs = UnaryOperator.TryCoerceUp(lhs, cover);
1462
				rhs = UnaryOperator.TryCoerceUp(rhs, cover);
1463
				expression.SetType(new BoolType(null));
1464
			}
1465
			else
1466
				return Error(expression, String.format("Operator expects LHS and RHS to be of same type (%s <> %s)", lhs.type().toString(), rhs.type().toString()));
1467
			break;
1468
		case seqmod_mapoverride:
1469
			if (rt.kind() != TypeKind.MapType)
1470
				return Error(expression, "Map expected as RHS on sequence modification or map override.");
1471
			// list of A * map int to A -> list of A or
1472
			if (lt.kind() == TypeKind.ListType)
1473
			{
1474
				// we're in sequence modification.
1475
				domlist = (ListType)lt;
1476
				rngMap = (MapType)rt;
1477
				if (rngMap.fromType().kind() != TypeKind.IntType)
1478
					return Error(expression, "Domain of map has to be integer");
1479
				if (!UlyssesType.TypeEqual(domlist.innerType(), rngMap.toType()))
1480
					return Error(expression, "Type of list expected to match range of map");
1481
				// since we only replace elements in the list (by matching ones from the map),
1482
				// we're save to return the original list..
1483
				expression.SetType(lt);
1484
			}
1485
			// map A to B * map A to B -> map A to B
1486
			else if (lt.kind() == TypeKind.MapType)
1487
			{
1488
				domMap = (MapType)lt;
1489
				rngMap = (MapType)rt;
1490
				if (!UlyssesType.TypeEqual(domMap.fromType(), rngMap.fromType()) ||
1491
						!UlyssesType.TypeEqual(domMap.toType(), rngMap.toType()))
1492
					return Error(expression, "Maps need same domain and range types");
1493
				// since we override entries in the first map:
1494
				expression.SetType(domMap);
1495
			}
1496
			else
1497
				return Error(expression, "Sequence Modification or Map override expects list or map as LHS");
1498
			break;
1499
		default:
1500
			throw new NotImplementedException();
1501
		}
1502

  
1503
		// set subtrees.
1504
		expression.SetLeftChild(lhs);
1505
		expression.SetRightChild(rhs);
1506

  
1507
		// we only allow:  a = MyTuple(c,d) style matchers
1508
		if (m_matcherList.size() > 0)
1509
		{
1510
			m_matcherList.clear();
1511
			return Error(expression, "Free variables in tuple constructor only allowed in expressions of the form 'atuple = ATupleConstructor(free1,free2...)'");
1512
		}
1513

  
1514
		// try simple constant folding
1515
		return ApplyConstantFolding(expression);
1516
	}
1517

  
1518

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff