/**
*
* OOAS Compiler (Deprecated)
*
* Copyright 2015, Institute for Software Technology, Graz University of
* Technology. Portions are copyright 2015 by the AIT Austrian Institute
* of Technology. All rights reserved.
*
* SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
*
* Please notice that this version of the OOAS compiler is considered de-
* precated. Only the Java version is maintained.
*
* Contributors:
* Willibald Krenn (TU Graz/AIT)
* Stefan Tiran (TU Graz/AIT)
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace TUG.Mogentes
{
///
/// Requires: ReplaceOpaqueVisitor
///
/// After we have an AST without any Opaquetypes, we still need to replace all the
/// UnresolvedIdentifierExpressions. We also need to compute the expression types,
/// which is also necessary to resolve all the identifiers. So, this visitor
/// goes over all expressions and
/// - resolves all identifiers
/// - calculates resulting types (incl. coercion)
///
public sealed class OoaResolveExpressionsVisitor : OoaCompleteAstTraversalVisitor
{
// we allow for free variable in expressions. collect them here.
private Stack m_freeVariables = new Stack();
private Expression m_entryExpression = null;
// helpers that replace the old expression in the AST by the new one.
private void ReplaceExpression(IAst parent, Expression subElement, Expression newExpression)
{
switch (parent.nodeType)
{
case AstNodeTypeEnum.identifier:
ReplaceExpressionInIdentifier((Identifier)parent, subElement, newExpression);
break;
case AstNodeTypeEnum.statement:
ReplaceExpressionInStatement((Statement)parent, subElement, newExpression);
break;
default:
throw new NotImplementedException();
}
}
private void ReplaceExpressionInIdentifier(Identifier identifier, Expression subElement, Expression newExpression)
{
switch (identifier.kind)
{
case IdentifierKind.AttributeIdentifier:
AttributeIdentifier ident = (AttributeIdentifier)identifier;
System.Diagnostics.Debug.Assert(ReferenceEquals(ident.initializer, subElement));
ident.SetInitializer(newExpression);
break;
case IdentifierKind.Constant:
ConstantIdentifier aconst = (ConstantIdentifier)identifier;
System.Diagnostics.Debug.Assert(ReferenceEquals(aconst.Value, subElement));
aconst.SetValue(newExpression);
if (newExpression.kind != ExpressionKind.Value)
{
Error(aconst.Value, String.Format("{0} not a constant!", aconst.tokenText));
}
break;
default:
throw new NotImplementedException();
}
}
private void ReplaceExpressionInStatement(Statement statement, Expression subElement, Expression newExpression)
{
switch (statement.kind)
{
case StatementKind.GuardedCommand:
GuardedCommand gc = (GuardedCommand)statement;
System.Diagnostics.Debug.Assert(ReferenceEquals(gc.guard, subElement));
gc.SetGuard(newExpression);
break;
case StatementKind.SeqBlock:
SeqBlock sqblock = (SeqBlock)statement;
System.Diagnostics.Debug.Assert(ReferenceEquals(sqblock.filter, subElement));
sqblock.SetFilter(null);
// we convert the filter to a guarded command...
SeqBlock implseq = new SeqBlock(sqblock.line, sqblock.pos);
implseq.SetStatements(sqblock.statements);
GuardedCommand implguard = new GuardedCommand(newExpression, implseq, sqblock.line, sqblock.pos);
sqblock.SetStatements(new LinkedList());
sqblock.AddStatement(implguard);
break;
case StatementKind.Assignment:
Assignment zw = (Assignment)statement;
bool found = false;
if (ReferenceEquals(zw.nondetExpression, subElement))
{
zw.SetNondetExpression(newExpression);
found = true;
}
else
{
LinkedListNode anode = zw.places.First;
while (anode != null)
{
if (ReferenceEquals(anode.Value, subElement))
{
anode.Value = newExpression;
found = true;
break;
}
anode = anode.Next;
}
anode = zw.values.First;
while (anode != null)
{
if (ReferenceEquals(anode.Value, subElement))
{
anode.Value = newExpression;
found = true;
break;
}
anode = anode.Next;
}
}
System.Diagnostics.Debug.Assert(found);
break;
case StatementKind.MethodCall:
Call call = (Call)statement;
System.Diagnostics.Debug.Assert(ReferenceEquals(call.callExpression, subElement));
call.SetCallExpression(newExpression);
break;
default:
throw new NotImplementedException();
}
}
// helper that returns null and adds an error message in the parserstate errorlist.
private Expression Error(Expression expression, string p)
{
ParserError error = new ParserError(m_ParserState.filename,
expression.line, expression.pos, p);
m_ParserState.AddErrorMessage(error);
return null;
}
private Expression Error(int line, int pos, string p)
{
ParserError error = new ParserError(m_ParserState.filename, line, pos, p);
m_ParserState.AddErrorMessage(error);
return null;
}
// helper that adds a warning message to the output
private void Warning(Identifier expression, string p)
{
ParserWarning warning = new ParserWarning(m_ParserState.filename,
expression.line, expression.column, p);
m_ParserState.AddWarningMessage(warning);
}
private void Warning(Expression expression, string p)
{
ParserWarning warning = new ParserWarning(m_ParserState.filename,
expression.line, expression.pos, p);
m_ParserState.AddWarningMessage(warning);
}
private void Info(Expression expression, String p)
{
ParserMessage msg = new ParserMessage(m_ParserState.filename,
expression.line, expression.pos, p);
m_ParserState.AddMessage(msg);
}
private List m_matcherList = new List();
///
/// Resolve Expressions
///
private Expression ResolveExpression(TernaryOperator expression)
{
if (expression.kind == ExpressionKind.conditional)
{
Expression left = ResolveExpression(expression.left);
Expression mid = ResolveExpression(expression.mid);
Expression right = ResolveExpression(expression.right);
if (left == null
|| mid == null
|| right == null)
return null;
if (left.type == null ||
left.type.kind != TypeKind.BoolType)
return Error(expression, "Conditional: Condition not a bool");
if (mid.type == null
|| right.type == null)
return Error(expression, "Conditional: Then or Else branch has void-type");
UlyssesType acover = UlyssesType.CoverType(mid.type, right.type);
if (acover == null)
return Error(expression, String.Format("Conditional: Then and Else branch must be of same type. ({0} <> {1})", mid.type.ToString(), right.type.ToString()));
if (!UlyssesType.TypeEqual(acover, mid.type))
{
mid = new UnaryOperator(ExpressionKind.Cast, mid, mid.line, mid.pos);
mid.SetType(acover);
}
if (!UlyssesType.TypeEqual(acover, right.type))
{
right = new UnaryOperator(ExpressionKind.Cast, right, right.line, right.pos);
right.SetType(acover);
}
expression.SetLeftChild(left);
expression.SetMidChild(mid);
expression.SetRightChild(right);
expression.SetType(mid.type);
return expression;
}
else if (expression.kind == ExpressionKind.foldLR || expression.kind == ExpressionKind.foldRL)
{
CallExpression leftcall =
expression.left.kind != ExpressionKind.Call ?
new CallExpression(expression.left, new List(), expression.line,
expression.pos, expression.definingScope)
: (CallExpression)expression.left;
leftcall = (CallExpression)ResolveExpression(leftcall, true);
if (leftcall == null)
return null;
Expression afun = ResolveExpression(leftcall.child);
leftcall.SetChild(afun);
if (afun == null || afun.type == null || afun.type.kind != TypeKind.FunctionType)
return Error(expression, "Fold/Map operation needs a method or named action as LHS");
FunctionType funType = (FunctionType)afun.type;
if (funType.returnType == null && expression.mid != null)
return Error(expression, "Fold operation needs a method with matching return type");
if (funType.returnType != null && expression.mid == null)
Warning(expression, "Map operation will discard result of function");
bool isMap = expression.mid == null;
Expression mid = expression.mid;
if (!isMap)
{
mid = ResolveExpression(mid);
if ((funType.parameter.Count - leftcall.arguments.Count) != 2)
return Error(expression, "Function used in fold operation needs 2 not-instantiated parameters");
}
else if ((funType.parameter.Count - leftcall.arguments.Count) != 1)
return Error(expression, "Function used in map operation needs one not-instantiated parameter");
Expression right = ResolveExpression(expression.right);
if (right == null || right.type == null || right.type.kind != TypeKind.ListType)
return Error(expression, "Fold/Map operation needs list as RHS");
if (!isMap)
{
UlyssesType initCover = UlyssesType.CoverType(funType.parameter.Last.Previous.Value, mid.type);
if (initCover == null)
return Error(expression, "Next to last parameter does not match initializer type in map operation.");
if (!UlyssesType.TypeEqual(mid.type, initCover))
mid = new UnaryOperator(ExpressionKind.Cast, mid, mid.line, mid.pos);
mid.SetType(initCover);
//List args = new List ();
leftcall.arguments.Add(new IdentifierExpression(new ParameterIdentifier("_result", initCover, null), 0, 0));
leftcall.arguments.Add(new IdentifierExpression(new ParameterIdentifier("_elem", funType.parameter.Last.Value, null), 0, 0));
//leftcall.SetArguments(args);
}
// UlyssesType listCover = UlyssesType.CoverType(funType.parameter.Last.Value, ((ListType)right.type).innerType);
// if (listCover == null)
if (!UlyssesType.TypeEqual(funType.parameter.Last.Value, ((ListType)right.type).innerType))
return Error(expression, "Last paramter does not match inner-type of list in fold/map operation");
expression.SetLeftChild(leftcall);
expression.SetMidChild(mid);
expression.SetRightChild(right);
if (!isMap)
expression.SetType(funType.returnType);
else
expression.SetType(new NullType());
return expression;
}
else
throw new ArgumentException();
}
private Expression ResolveExpression(ForallQuantifier expression)
{
Expression child = ResolveExpression(expression.child);
if (child == null)
return null;
expression.SetType(new BoolType(null));
expression.SetChild(child);
return expression;
}
private Expression ResolveExpression(ExistsQuantifier expression)
{
Expression child = ResolveExpression(expression.child);
if (child == null)
return null;
expression.SetType(new BoolType(null));
expression.SetChild(child);
return expression;
}
private Expression ResolveExpression(ListConstructor expression)
{
UlyssesType type = null;
ListType restype = null;
Expression comprehension = null;
if (expression.comprehension != null)
{
comprehension = ResolveExpressionNewScope(expression.comprehension);
if (comprehension == null)
return null;
if (comprehension.type == null)
return Error(expression, "List comprehension has void expression");
if (comprehension.type.kind != TypeKind.BoolType)
return Error(expression, "List comprehension has to be bool-expression");
expression.SetComprehension(comprehension);
if (expression.elements.Count != 1)
return Error(expression, "List comprehension expects one initializer expression");
}
List newitems = new List();
if (expression.elements.Count == 0 || expression.elements[0] == null || (
expression.elements[0].kind == ExpressionKind.Value &&
expression.elements[0] is ValueExpression