private void CheckStatic(MethodCallExpression e, TypeCheckingContext context) { Type[] parameterClasses = e.Parameters.Select(i => i.Type).ToArray(); e.Method = ReflectionSnippets.FindMethod(e.OwnerType, e.MethodName, parameterClasses); if (e.Method == null) { StringBuilder paramList = new StringBuilder(); foreach (Type type in parameterClasses) { paramList.Append(type).Append(","); } if (parameterClasses.Length > 0) { paramList.Remove(paramList.Length - 1, 1); } StringBuilder locations = new StringBuilder(); locations.Append(e.OwnerType).Append("\r\n"); context.ErrorProvider.ThrowException(string.Format("Method {0}.{1}({2}) cannot be found.\r\nSearched the following location:\r\n{3}", e.OwnerType, e.MethodName, paramList, locations), e); } }
private void CheckFunctionCallExpression(FunctionCallExpression e, TypeCheckingContext context) { for (int i = 0; i <= e.Parameters.Length - 1; i++) { PerformTypeChecking(e.Parameters[i], context); } Type[] parameterClasses = e.Parameters.Select(i => i.Type).ToArray(); if (e.MethodName == "Loop" || e.MethodName.Contains("MCM") || e.MethodName.Contains("Draw_")) { var list = parameterClasses.ToList(); list.Add(typeof(object)); parameterClasses = list.ToArray(); } e.Method = context.VariableContext.SearchMethod(e.MethodName, null, parameterClasses); if (e.Method == null) { var coe = LocalRepo.Coefficients.FirstOrDefault(m => m.CoefficientName == e.MethodName); if (coe != null) { context.VariableContext.Set(e.MethodName, LocalRepo.CoefficientDetails.Where(m => m.CoefficientID == coe.CoefficientID).ToList()); e.Method = this.GetType().GetMethods()[0]; //模拟一个方法 e.IsCustomFunc = true; } else { e.IsCustomFunc = false; } if (!e.IsCustomFunc) { StringBuilder list = new StringBuilder(); foreach (Type type in parameterClasses) { list.Append(type).Append(","); } list.Remove(list.Length - 1, 1); StringBuilder locations = new StringBuilder(); foreach (Type type in context.VariableContext.GetMethodExtenders()) { locations.Append(type).Append("\r\n"); } context.ErrorProvider.ThrowException(string.Format("Method {0}({1}) cannot be found.\r\nSearched the following locations:\r\n{2}", e.MethodName, list, locations), e); } } e.Type = e.Method.ReturnType; context.LambdaContext.PushCallerMethod(e); for (int i = 0; i <= e.Parameters.Length - 1; i++) { PerformTypeChecking(e.Parameters[i], context); } context.LambdaContext.PopCallerMethod(); }
private void CheckFieldExpression(FieldExpression e, TypeCheckingContext context) { if (!e.IsStatic) { PerformTypeChecking(e.Operand, context); } e.Field = (e.IsStatic ? e.OwnerType : e.Operand.Type).GetField(e.FieldName); if (e.Field != null) { e.Type = e.Field.FieldType; } else { e.Property = (e.IsStatic ? e.OwnerType : e.Operand.Type).GetProperty(e.FieldName); if (e.Property != null) { e.Type = e.Property.PropertyType; } else { context.ErrorProvider.ThrowException(string.Format("Field or property {0}.{1} not found.", e.Operand.Type, e.FieldName), e); } } }
private void CheckIfElseExpression(IfElseExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Condition, context); PerformTypeChecking(e.PositiveBranch, context); PerformTypeChecking(e.NegativeBranch, context); if (e.Condition.Type != typeof(bool)) { context.ErrorProvider.ThrowException(string.Format("Condition cannot be {0}", e.Condition.GetType()), e); } Type positiveType = e.PositiveBranch.Type; Type negativeType = e.NegativeBranch.Type; if (positiveType == negativeType) { e.Type = positiveType; } else { context.ErrorProvider.ThrowException(string.Format("{0} and {1} are not the same type.", positiveType, negativeType), e); } }
private void CheckArrayExpression(ArrayExpression e, TypeCheckingContext context) { List <List <Type> > baseTypes = new List <List <Type> >(); foreach (Expression item in e.Items) { PerformTypeChecking(item, context); List <Type> types = new List <Type>(); Type current = item.Type; while (current != null) { types.Add(current); current = current.BaseType; } baseTypes.Add(types); } Type commonBaseType = baseTypes[0].FirstOrDefault(i => baseTypes.Skip(1).All(j => j.Contains(i))); if (commonBaseType != typeof(ValueType)) { e.Type = commonBaseType.MakeArrayType(); } else { e.Type = Types.GetPrimitiveType(e.Items.Min(i => Types.GetPrimitiveTypeIndex(i.Type))).MakeArrayType(); } }
private void CheckMethodCallExpression(MethodCallExpression e, TypeCheckingContext context) { for (int i = 0; i <= e.Parameters.Length - 1; i++) { PerformTypeChecking(e.Parameters[i], context); } if (e.IsStatic) { CheckStatic(e, context); } else { CheckNonStatic(e, context); } e.Type = e.Method.ReturnType; context.LambdaContext.PushCallerMethod(e); for (int i = 0; i <= e.Parameters.Length - 1; i++) { PerformTypeChecking(e.Parameters[i], context); } context.LambdaContext.PopCallerMethod(); }
public override void OnCreateTypeCheckingContext(TypeCheckingContext context) { context.AddAutoCreatedValue(typeof(Vector), new Vector(0)); context.AddAutoCreatedValue(typeof(Matrix), new Matrix(0, 0)); context.AddAutoCreatedValue(typeof(Bitmap), new Bitmap(1, 1)); context.AddAutoCreatedValue(typeof(VariableContextExpression), new VariableContextExpression(null, null, 0, 0)); context.AddAutoCreatedValue(typeof(Expression), ConstantExpression.create(1, 0, 0)); }
private void CheckMultiIndexingExpression(MultiIndexingExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Operand, context); foreach (Expression indexer in e.Indexers) { PerformTypeChecking(indexer, context); } if (!e.Indexers.All(i => Types.IsNumberType(i.Type))) { context.ErrorProvider.ThrowException("Matrix multi indexer parameters must be of number types.", e); } if (e.Operand.Type.IsArray) { if (e.Indexers.Length != 1) { context.ErrorProvider.ThrowException("Array multi indexer must be of 1 parameter.", e); } else { e.Type = e.Operand.Type.GetElementType(); } } else if (e.Operand.Type == typeof(Matrix)) { if (e.Indexers.Length == 1) { e.Type = typeof(double[]); } else if (e.Indexers.Length == 2) { e.Type = typeof(double); } else { context.ErrorProvider.ThrowException("Matrix multi indexer must be of 1 or 2 parameters.", e); } } else if (e.Operand.Type == typeof(Vector)) { if (e.Indexers.Length == 1) { e.Type = typeof(double); } else { context.ErrorProvider.ThrowException("Vector multi indexer must be of 1 parameter.", e); } } else { context.ErrorProvider.ThrowException("Only matrix can use multi indexer.", e); } }
private void CheckLambdaExpression(LambdaExpression e, TypeCheckingContext context) { e.Type = typeof(LambdaExpression); if (e.Level != context.LambdaContext.GetCallerStackSize()) { return; } context.LambdaContext.PushVariables(e.VariableNames); e.VariableTypes = new Type[e.VariableNames.Length]; int index = 0; foreach (string variableName in e.VariableNames) { LambdaVariable variable = context.LambdaContext.GetVariable(variableName); Expression lambdaOperand; string methodName; if (variable.CallerMethod is MethodCallExpression) { MethodCallExpression mc = variable.CallerMethod as MethodCallExpression; lambdaOperand = mc.IsExtension ? mc.Operand : mc.Parameters[0]; methodName = mc.MethodName; } else { FunctionCallExpression fc = variable.CallerMethod as FunctionCallExpression; lambdaOperand = fc.Parameters[0]; methodName = fc.MethodName; } Type type = ResolveLambdaParameterType(lambdaOperand.Type, index); if (type == null) { context.ErrorProvider.ThrowException(string.Format("Cannot apply lambda parameter {0} to method {1}", variableName, methodName), e); } e.VariableTypes[index] = type; context.LambdaContext.GetVariable(variableName).Type = type; index++; } PerformTypeChecking(e.Body, context); context.LambdaContext.PopVariables(e.VariableNames.Length); }
private void CheckDictionaryExpression(DictionaryExpression e, TypeCheckingContext context) { foreach (Expression value in e.Dictionary.Values) { PerformTypeChecking(value, context); } e.Type = typeof(Dictionary <string, object>); }
private void CheckNonStatic(MethodCallExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Operand, context); Type[] parameterClasses = e.Parameters.Select(i => i.Type).ToArray(); e.Method = ReflectionSnippets.FindMethod(e.Operand.Type, e.MethodName, parameterClasses); if (e.Method == null && context.VariableContext != null) { e.Method = context.VariableContext.SearchMethod(e.MethodName, e.Operand.Type, parameterClasses); e.IsExtension = true; } if (e.Method == null) { StringBuilder list1 = new StringBuilder(); foreach (Type type in parameterClasses) { list1.Append(type).Append(","); } if (parameterClasses.Length > 0) { list1.Remove(list1.Length - 1, 1); } StringBuilder list2 = new StringBuilder(); list2.Append(e.Operand.Type).Append(","); foreach (Type type in parameterClasses) { list2.Append(type).Append(","); } list2.Remove(list2.Length - 1, 1); StringBuilder locations = new StringBuilder(); locations.Append(e.Operand.Type).Append("\r\n"); foreach (Type type in context.VariableContext.GetMethodExtenders()) { locations.Append(type).Append("\r\n"); } context.ErrorProvider.ThrowException(string.Format("Method {0}.{1}({2}) or extension method {3}({4}) cannot be found.\r\nSearched the following locations:\r\n{5}", e.Operand.Type, e.MethodName, list1, e.MethodName, list2, locations), e); } }
public override void PerformTypeChecking(Expression expression, TypeCheckingContext context) { if (expression is CastExpression) { CheckCastExpression((CastExpression)expression, context); } else if (expression is CreateObjectExpression) { CehckCreateObjectExpression((CreateObjectExpression)expression, context); } else if (expression is CreateArrayExpression) { CheckCreateArrayExpression((CreateArrayExpression)expression, context); } else if (expression is BinaryExpression) { CheckBinaryExpression((BinaryExpression)expression, context); } else if (expression is VariableExpression) { CheckVariableExpression((VariableExpression)expression, context); } else if (expression is MethodCallExpression) { CheckMethodCallExpression((MethodCallExpression)expression, context); } else if (expression is FunctionCallExpression) { CheckFunctionCallExpression((FunctionCallExpression)expression, context); } else if (expression is IndexingExpression) { CheckIndexingExpression((IndexingExpression)expression, context); } else if (expression is FieldExpression) { CheckFieldExpression((FieldExpression)expression, context); } else if (expression is LambdaExpression) { CheckLambdaExpression((LambdaExpression)expression, context); } else if (expression is ConstantExpression) { CheckConstantExpression((ConstantExpression)expression); } else if (expression is UnaryExpression) { CheckUnaryExpression((UnaryExpression)expression, context); } else if (expression is IfElseExpression) { CheckIfElseExpression((IfElseExpression)expression, context); } }
private void CheckUnaryExpression(UnaryExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Operand, context); Type type = null; bool isValid = true; if (e.Operator == UnaryOperator.Negation) { if (Types.IsNumberType(e.Operand.Type)) { type = e.Operand.Type; } else { isValid = false; } } else if (e.Operator == UnaryOperator.Not) { if (Types.GetPrimitiveTypeIndex(e.Operand.Type) == 7) { type = typeof(bool); } else { isValid = false; } } else if (e.Operator == UnaryOperator.Identity) { if (Types.IsNumberType(e.Operand.Type)) { type = e.Operand.Type; } else { isValid = false; } } if (isValid) { e.Type = type; } else { context.ErrorProvider.ThrowException(string.Format("Operator {0} cannot be applied to type {1}.", ExpressionSnippets.SerializeUnaryOperator(e.Operator), e.Operand.Type), e); } }
private void CheckMultipleVariableExpression(MultipleVariableExpression e, TypeCheckingContext context) { List <Type> elementTypes = new List <Type>(); int index = 0; foreach (string variable in e.Variables) { Type elementType = context.RightOperandType.GenericTypeArguments[index]; elementTypes.Add(elementType); context.VariableContext.Set(variable, context.CreateAutoCreatedVariableValue(elementType)); index++; if (index > context.RightOperandType.GenericTypeArguments.Length - 1) { break; } } Type baseType = null; int elementCount = elementTypes.Count; if (elementCount == 1) { baseType = typeof(Tuple <>); } else if (elementCount == 2) { baseType = typeof(Tuple <,>); } else if (elementCount == 3) { baseType = typeof(Tuple <, ,>); } else if (elementCount == 4) { baseType = typeof(Tuple <, , ,>); } else if (elementCount == 5) { baseType = typeof(Tuple <, , , ,>); } else if (elementCount == 6) { baseType = typeof(Tuple <, , , , ,>); } e.Type = baseType.MakeGenericType(elementTypes.ToArray()); }
private void CehckCreateObjectExpression(CreateObjectExpression e, TypeCheckingContext context) { foreach (Expression parameter in e.Parameters) { PerformTypeChecking(parameter, context); } foreach (ConstructorInfo c in e.ObjectType.GetConstructors()) { bool isValid = true; int i = 0; foreach (ParameterInfo p in c.GetParameters()) { if (!ReflectionSnippets.Accepts(p.ParameterType, e.Parameters[i].Type)) { isValid = false; break; } i++; } if (isValid) { e.Constructor = c; break; } } if (e.Constructor == null) { StringBuilder b = new StringBuilder(); foreach (Expression parameter in e.Parameters) { b.Append(parameter.Type).Append(","); } if (e.Parameters.Length > 0) { b.Remove(b.Length - 1, 1); } context.ErrorProvider.ThrowException(string.Format("{0}.ctor({1}) not found", e.ObjectType, b), e); } e.Type = e.ObjectType; }
private void CheckMatrixExpression(MatrixExpression e, TypeCheckingContext context) { foreach (Expression[] row in e.Rows) { foreach (Expression item in row) { PerformTypeChecking(item, context); if (!Types.IsNumberType(item.Type)) { context.ErrorProvider.ThrowException("An element of a matrix must be convertialbe to double.", item); } } } e.Type = typeof(Matrix); }
private void CheckCreateArrayExpression(CreateArrayExpression e, TypeCheckingContext context) { foreach (Expression element in e.Elements) { PerformTypeChecking(element, context); Type type = element is CondensedArrayExpression?element.Type.GetElementType() : element.Type; if (!ReflectionSnippets.Accepts(e.ElementType, type)) { context.ErrorProvider.ThrowException(string.Format("{0} cannot be put into {1}[]", element.Type, e.ElementType), element); } } e.Type = e.ElementType.MakeArrayType(0); }
private void CheckIndexingExpression(IndexingExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Operand, context); PerformTypeChecking(e.Indexer, context); if (!e.Operand.Type.IsArray) { context.ErrorProvider.ThrowException("Only array types can use [] operator.", e); } else if (!ReflectionSnippets.Accepts(typeof(int), e.Indexer.Type)) { context.ErrorProvider.ThrowException("Indexer must be convertiable to int.", e); } else { e.Type = e.Operand.Type.GetElementType(); } }
private void CheckVariableContextExpression(VariableContextExpression e, TypeCheckingContext context) { foreach (VariableInfo variable in e.Variables) { context.VariableContext.Set(variable.Name, context.CreateAutoCreatedVariableValue(variable.Type)); } PerformTypeChecking(e.Expression, context); foreach (VariableInfo variable in e.Variables) { context.VariableContext.Remove(variable.Name); } e.Type = typeof(VariableContextExpression); e.Evaluator = new MathyExpressionEvaluator(); }
private void CheckBinaryExpression(BinaryExpression e, TypeCheckingContext context) { PerformTypeChecking(e.Right, context); if (context.CreateVariableOnAssign && e.Operator == BinaryOperator.Assign) { context.RightOperandType = e.Right.Type; } else { context.RightOperandType = null; } PerformTypeChecking(e.Left, context); context.RightOperandType = null; CheckBinaryExpresionType(e, context); }
public Expression[] Compile(string s, VariableContext variableContext) { ExpressionCompiler compiler = CreateCompiler(); Lexicon[] lexicons; try { lexicons = new Lexiconizer(LexiconizationRuleTable.GetRule(compiler)).Lexiconize(s); } catch (LexiconizationException e) { throw new CompileException(e.Message); } CompileErrorProvider errorProvider = new CompileErrorProvider(s, lexicons, compiler.PerformTypeChecking); Expression[] roots = compiler.Compile(s, lexicons, errorProvider); if (variableContext == null) { variableContext = new VariableContext(); } foreach (Expression root in roots) { TypeCheckingContext context = new TypeCheckingContext(); OnCreateTypeCheckingContext(context); context.CreateVariableOnAssign = compiler.CreateVariableOnAssing(); context.VariableContext = variableContext; context.LambdaContext = new LambdaContext(); context.ErrorProvider = errorProvider; CreateTypeChecker().PerformTypeChecking(root, context); } return(roots); }
public override void PerformTypeChecking(Expression expression, TypeCheckingContext context) { if (expression is MatrixExpression) { CheckMatrixExpression(expression as MatrixExpression, context); } else if (expression is MultiIndexingExpression) { CheckMultiIndexingExpression(expression as MultiIndexingExpression, context); } else if (expression is VariableContextExpression) { CheckVariableContextExpression(expression as VariableContextExpression, context); } else if (expression is MultipleVariableExpression) { CheckMultipleVariableExpression(expression as MultipleVariableExpression, context); } else if (expression is DictionaryExpression) { CheckDictionaryExpression(expression as DictionaryExpression, context); } else if (expression is ArrayExpression) { CheckArrayExpression(expression as ArrayExpression, context); } else if (expression is IterationSumExpression) { CheckIterationSumExpression(expression as IterationSumExpression, context); } else if (expression is PredefinedConstantExpression) { CheckPredefinedConstantExpression(expression as PredefinedConstantExpression, context); } else { base.PerformTypeChecking(expression, context); } }
private void CheckVariableExpression(VariableExpression e, TypeCheckingContext context) { LambdaVariable variable = context.LambdaContext.GetVariable(e.VariableName); if (variable != null) { e.Type = context.LambdaContext.GetVariable(variable.Name).Type; } else if (context.VariableContext.HasVariable(e.VariableName)) { e.Type = context.VariableContext.GetType(e.VariableName); } else if (context.CreateVariableOnAssign && context.RightOperandType != null) { context.VariableContext.Set(e.VariableName, context.CreateAutoCreatedVariableValue(context.RightOperandType)); e.Type = context.VariableContext.GetType(e.VariableName); } else { context.ErrorProvider.ThrowException(string.Format("{0} not defined.", e.VariableName), e); } }
private void CheckCastExpression(CastExpression e, TypeCheckingContext context) { try { e.TargetType = Types.GetType(e.ClassName, LanguageService.GetImportedPackages()); } catch { context.ErrorProvider.ThrowException(string.Format("{0} not defined.", e.ClassName), e); } PerformTypeChecking(e.Operand, context); if (e.Operand.Type == null ? !Types.IsPrimitiveType(e.TargetType) : ReflectionSnippets.CanCast(e.TargetType, e.Operand.Type)) { e.Type = e.TargetType; } else { context.ErrorProvider.ThrowException(string.Format("Cannot cast from {0} to {1}.", e.Operand.Type, e.TargetType), e); } }
public TypeCheckingContext CreateTypeCheckingContext(VariableContext variableContext) { ExpressionCompiler compiler = CreateCompiler(); TypeCheckingContext context = new TypeCheckingContext(); OnCreateTypeCheckingContext(context); CompileErrorProvider errorProvider = new CompileErrorProvider(null, null, compiler.PerformTypeChecking); if (variableContext == null) { variableContext = new VariableContext(); } context.CreateVariableOnAssign = compiler.CreateVariableOnAssing(); context.VariableContext = variableContext; context.LambdaContext = new LambdaContext(); context.ErrorProvider = errorProvider; return(context); }
private void CheckIterationSumExpression(IterationSumExpression e, TypeCheckingContext context) { foreach (IterationSumVariable variable in e.Variables) { PerformTypeChecking(variable.From, context); PerformTypeChecking(variable.To, context); if (!Types.IsNumberType(variable.From.Type)) { context.ErrorProvider.ThrowException(string.Format("Start value of {0} is not number.", variable.Name), e); } if (!Types.IsNumberType(variable.To.Type)) { context.ErrorProvider.ThrowException(string.Format("End value of {1} is not number.", variable.Name), e); } context.VariableContext.Set(variable.Name, 0); } PerformTypeChecking(e.Body, context); foreach (IterationSumVariable variable in e.Variables) { context.VariableContext.Remove(variable.Name); } if (!Types.IsNumberType(e.Body.Type)) { context.ErrorProvider.ThrowException("Can only perform iteration sum on an expression of number type.", e); } e.Type = typeof(double); }
public abstract void OnCreateTypeCheckingContext(TypeCheckingContext context);
protected virtual void CheckBinaryExpresionType(BinaryExpression e, TypeCheckingContext context) { Type type = null; bool isValid = true; if (e.Left.Type == null && e.Right.Type == null) { isValid = false; } else if (e.Operator == BinaryOperator.Assign) { if (!(e.Left is VariableExpression || e.Left is IndexingExpression)) { context.ErrorProvider.ThrowException("Can only assign to a variable.", e); return; } } else if (e.Operator == BinaryOperator.Add) { if (e.Left.Type == typeof(char) || e.Right.Type == typeof(char)) { type = typeof(string); } else if (e.Left.Type == typeof(string) || e.Right.Type == typeof(string)) { type = typeof(string); } else if (Types.IsNumberType(e.Left.Type) && Types.IsNumberType(e.Right.Type)) { int index = Types.ResolvePrimitiveTypeIndex(e.Left.Type, e.Right.Type); type = Types.GetPrimitiveType(index); } else { isValid = false; } } else if (e.Operator == BinaryOperator.Subtract || e.Operator == BinaryOperator.Multiply || e.Operator == BinaryOperator.Divide) { if (Types.IsNumberType(e.Left.Type) && Types.IsNumberType(e.Right.Type)) { int index = Types.ResolvePrimitiveTypeIndex(e.Left.Type, e.Right.Type); type = Types.GetPrimitiveType(index); } else if (e.Left.Type.Name == "Matrix" && e.Right.Type.Name == "Matrix") { type = e.Left.Type; } else { isValid = false; } } else if (e.Operator == BinaryOperator.LessThan || e.Operator == BinaryOperator.LessEqualThan || e.Operator == BinaryOperator.GreaterThan || e.Operator == BinaryOperator.GreaterEqualThan) { if (e.Left.Type == typeof(string) && e.Right.Type == typeof(string)) { type = typeof(bool); } else if (Types.IsNumberType(e.Left.Type) && Types.IsNumberType(e.Right.Type)) { type = typeof(bool); } else { isValid = false; } } else if (e.Operator == BinaryOperator.Equal || e.Operator == BinaryOperator.NotEqual) { if (e.Left.Type == typeof(string) && e.Right.Type == typeof(string)) { type = typeof(bool); } else if (Types.IsNumberType(e.Left.Type) && Types.IsNumberType(e.Right.Type)) { type = typeof(bool); } else if (Types.GetPrimitiveTypeIndex(e.Left.Type) == 7 && Types.GetPrimitiveTypeIndex(e.Right.Type) == 7) { type = typeof(bool); } else if (e.Left is ConstantExpression && ((ConstantExpression)e.Left).Value == null && !Types.IsPrimitiveType(e.Right.Type)) { type = typeof(bool); } else if (e.Right is ConstantExpression && ((ConstantExpression)e.Right).Value == null && !Types.IsPrimitiveType(e.Left.Type)) { type = typeof(bool); } else { isValid = false; } } else if (e.Operator == BinaryOperator.And || e.Operator == BinaryOperator.Or) { if (e.Left.Type == typeof(bool) || e.Right.Type == typeof(bool)) { type = typeof(bool); } else { isValid = false; } } if (isValid) { e.Type = type; } else if (context != null) { context.ErrorProvider.ThrowException(string.Format("Operator {0} cannot be applied to types of {1} and {2}.", ExpressionSnippets.SerializeBinaryOperator(e.Operator), e.Left.Type, e.Right.Type), e); } }
public override void OnCreateTypeCheckingContext(TypeCheckingContext context) { }
public abstract void PerformTypeChecking(Expression expression, TypeCheckingContext context);