/*======================================================================== Copyright (C) 2006 by Geir-Tore Lindsve, Torbjørn Meistad and Yngve Raudberget, hereby refered to as "the authors". All rights reserved Permission is hereby granted, without written agreement and without license or royalty fees, to use, reproduce, prepare derivative works, distribute, and display this software and its documentation for NONCOMMERCIAL RESEARCH AND EDUCATIONAL PURPOSES, provided that (1) the above copyright notice and the following two paragraphs appear in all copies of the source code and (2) redistributions, including without limitation binaries, reproduce these notices in the supporting documentation. IN NO EVENT SHALL THE AUTHORS, OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ========================================================================*/ using System; using System.Collections.Generic; using System.Text; using Iesi.Collections; using System.Collections; using CLab.Exceptions; namespace CLab.Data { /// /// Class for checking if the problem is valid. Runs type and variable checks. /// public class Symbols { private CP cp; //Type variables private Set allTypes; private Set enumerationTypes; private Hashtable enumerationItems; private Set allEnumerationItems; private Set rangeTypes; //Variable variables private Set allVariables; private Set enumerationVariables; private Hashtable enumerationVariableType; private Set rangeVariables; private Set boolVariables; //Other private StringComparer stringComparer; /// /// Initializes a new instance of the class. /// /// The CP object. public Symbols(CP cp) { stringComparer = StringComparer.Create(System.Globalization.CultureInfo.CurrentCulture, true); this.cp = cp; //Type variables allTypes = new HybridSet(); enumerationTypes = new HybridSet(); enumerationItems = new Hashtable(stringComparer); allEnumerationItems = new HybridSet(); rangeTypes = new HybridSet(); //Variable variables allVariables = new HybridSet(); enumerationVariables = new HybridSet(); enumerationVariableType = new Hashtable(stringComparer); rangeVariables = new HybridSet(); boolVariables = new HybridSet(); FillAndCheckType(); FillAndCheckVar(); } /// /// Fills the type list after the type has been checked. /// public void FillAndCheckType() { for (int i = 0; i < cp.Types.Count; i++) { if (allTypes.Contains(cp.Types[i].TypeName.ToLower())) { throw new ClabSymbolException(String.Format("Duplicate type definition: {0}.", ((Type)cp.Types[i]).TypeName)); } else allTypes.Add(cp.Types[i].TypeName.ToLower()); switch (cp.Types[i].GetType().ToString()) { case "CLab.Data.TypeEnum": { TypeEnum tvl = (TypeEnum)cp.Types[i]; if (tvl.EnumeratorsList.Count < 2) { throw new ClabSymbolException(String.Format("Enumerator list does not contain at least two items: {0}.", cp.Types[i].TypeName)); } else enumerationTypes.Add(cp.Types[i].TypeName.ToLower()); enumerationTypes.Add(cp.Types[i].TypeName.ToLower()); Set valueSet = new HybridSet(); foreach (String value in tvl.EnumeratorsList) { if (allTypes.Contains(value.ToLower())) { throw new ClabSymbolException(String.Format("{0} is already defined in {1}.", value, cp.Types[i].TypeName)); } else valueSet.Add(value.ToLower()); } allEnumerationItems = (Set) allEnumerationItems.Union(valueSet); enumerationItems[cp.Types[i].TypeName] = MakeSetOfList(((TypeEnum)cp.Types[i]).EnumeratorsList); } break; case "CLab.Data.TypeRange": { TypeRange tr = (TypeRange)cp.Types[i]; if (tr.EndOfRange - tr.StartOfRange + 1 < 2) { throw new ClabSymbolException(String.Format("Range ({0}) is too small ({1}).", cp.Types[i].TypeName, (tr.EndOfRange - tr.StartOfRange))); } else rangeTypes.Add(cp.Types[i].TypeName.ToLower()); } break; default: throw new ClabInternalErrorException("Symbols.cs: FillAndCheckType() : switch case not covered"); } } } /// /// Fills the variable list after the variable has been checked. /// public void FillAndCheckVar() { for (int i = 0; i < cp.Variables.Count; i++) { Variable var = cp.Variables[i]; if (allVariables.Contains(var.VariableName.ToLower())) { throw new ClabSymbolException(String.Format("Variable already declared ({0}).", var.VariableName)); } if (allEnumerationItems.Contains(var.VariableName.ToLower())) { throw new ClabSymbolException(String.Format("Variable name already exists ({0})", var.VariableName)); } allVariables.Add(var.VariableName.ToLower()); if (string.Compare(cp.Variables[i].TypeName, "bool", true) == 0) boolVariables.Add(var.VariableName.ToLower()); else { if (!allTypes.Contains(var.TypeName.ToLower())) { throw new ClabSymbolException(String.Format("Variable type is neither declared or bool ({0}).", var.TypeName)); } //Variable of valuelist type if (enumerationTypes.Contains(var.TypeName.ToLower())) { enumerationVariables.Add(var.VariableName.ToLower()); enumerationVariableType[var.VariableName] = var.TypeName; } //Variable of range type else rangeVariables.Add(var.VariableName.ToLower()); } } } /// /// Checks if the expressions have valid types. /// /// The expression. /// public void CheckExpressionType(Expression expression) { switch (expression.Type) { case Common.ExprType.et_id: ExpressionId idExpression = (ExpressionId)expression; if (!allVariables.Contains(idExpression.Id.ToLower()) & !allEnumerationItems.Contains(idExpression.Id.ToLower())) throw new ClabSymbolException(String.Format("Variable or enumeration constant {0} is not declared", idExpression.Id)); if (enumerationVariables.Contains(idExpression.Id.ToLower())) throw new ClabSymbolException(String.Format("Illegal enumeration expression for enumeration variable {0}", idExpression.Id)); if (allEnumerationItems.Contains(idExpression.Id.ToLower())) throw new ClabSymbolException(String.Format("Illegal enumeration expression for enumeration constant {0}", idExpression.Id)); break; case Common.ExprType.et_eq: case Common.ExprType.et_ne: ExpressionBinary binExpression = (ExpressionBinary)expression; bool enumerationVariablesLeft = false; bool enumerationVariablesRight = false; bool allEnumerationItemsLeft = false; bool allEnumerationItemsRight = false; String var = ""; String item = ""; //Checking left side if (binExpression.Left.Type.Equals(Common.ExprType.et_id)) { ExpressionId leftIdExpression = (ExpressionId)binExpression.Left; if (!allVariables.Contains(leftIdExpression.Id.ToLower()) & !allEnumerationItems.Contains(leftIdExpression.Id.ToLower())) throw new ClabSymbolException(String.Format("Left argument {0} of ==/!= expression {1} is not a declared variable or enumeration constant", leftIdExpression.Id, expression)); else if (enumerationVariables.Contains(leftIdExpression.Id.ToLower())) { enumerationVariablesLeft = true; var = leftIdExpression.Id; } else if (allEnumerationItems.Contains(leftIdExpression.Id.ToLower())) { allEnumerationItemsLeft = true; item = leftIdExpression.Id; } } //Checking right side if (binExpression.Right.Type.Equals(Common.ExprType.et_id)) { ExpressionId rightIdExpression = (ExpressionId)binExpression.Right; if (!allVariables.Contains(rightIdExpression.Id.ToLower()) & !allEnumerationItems.Contains(rightIdExpression.Id.ToLower())) { if (!allVariables.Contains(rightIdExpression.Id.ToLower())) Console.WriteLine("!allVariables. Count = " + allVariables.Count); if (!allEnumerationItems.Contains(rightIdExpression.Id.ToLower())) Console.WriteLine("!allEnumerationItems. Count = " + allEnumerationItems.Count); throw new ClabSymbolException(String.Format("Right argument {0} of ==/!= expression {1} is not a declared variable or enumeration constant", rightIdExpression.Id, expression)); } else if (enumerationVariables.Contains(rightIdExpression.Id.ToLower())) { enumerationVariablesRight = true; var = rightIdExpression.Id; } else if (allEnumerationItems.Contains(rightIdExpression.Id.ToLower())) { allEnumerationItemsRight = true; item = rightIdExpression.Id; } } //If either an enum variable or const on left or right side we can check without a recursive call if (enumerationVariablesLeft | enumerationVariablesRight | allEnumerationItemsLeft | allEnumerationItemsRight) { if (enumerationVariablesLeft & allEnumerationItemsRight | enumerationVariablesRight & allEnumerationItemsLeft) { if (!((Set)enumerationItems[enumerationVariableType[var]]).Contains(item.ToLower())) throw new ClabSymbolException(String.Format("In some == or != expression: the enumeration constant {0} is not a member of {1}'s enumeration type {2} ={3}", item, var, enumerationVariableType[var], ((TypeEnum)enumerationItems[enumerationVariableType[var]]).GetDomain)); } else //Illegal enum expression { String error = "Error in some ==/!= expression involving\n"; if (!var.Equals("")) error += "\tEnumeration variable: " + var + "\n"; if (!item.Equals("")) error += "\tEnumeration constant: " + item + "\n"; throw new ClabSymbolException(error); } } else { //Not an enum expression - Make recursive check CheckExpressionType(binExpression.Left); CheckExpressionType(binExpression.Right); } break; case Common.ExprType.et_val: //Leaf case always ok break; case Common.ExprType.et_neg: case Common.ExprType.et_not: ExpressionNotNeg nnExpression = (ExpressionNotNeg)expression; CheckExpressionType(nnExpression.Left); break; case Common.ExprType.et_impl: case Common.ExprType.et_or: case Common.ExprType.et_and: case Common.ExprType.et_lte: case Common.ExprType.et_gte: case Common.ExprType.et_lt: case Common.ExprType.et_gt: case Common.ExprType.et_minus: case Common.ExprType.et_plus: case Common.ExprType.et_mod: case Common.ExprType.et_div: case Common.ExprType.et_times: binExpression = (ExpressionBinary)expression; //Not an enum expression - Make recursive check CheckExpressionType(binExpression.Left); CheckExpressionType(binExpression.Right); break; default: throw new ClabInternalErrorException("Symbols.cs: CheckExpressionType : switch case not covered"); } } /// /// Makes a set of a list. /// /// The original list. /// The created set public Set MakeSetOfList(List list) { Set res = new HybridSet(); foreach (String s in list) { res.Add(s.ToLower()); } return res; } /// /// Gets the enumeration variables. /// public Set EnumerationVariables { get { return this.enumerationVariables; } } /// /// Gets the set of all variables. /// public Set AllVariables { get { return allVariables; } } /// /// Gets or sets the range variables. /// /// The range variables. public Set RangeVariables { get { return rangeVariables; } set { rangeVariables = value; } } /// /// Gets or sets the bool variables. /// /// The bool variables. public Set BoolVariables { get { return boolVariables; } set { boolVariables = value; } } } }