private Type binary_optional_left_expr(ParserRuleContext context, ParserRuleContext left, IToken op, ParserRuleContext right) { if (left == null) { Type t = right.Accept(this); type_dict[context] = t; return(t); } Type left_type = left.Accept(this); Type right_type = right.Accept(this); Type resulting_type = get_binary_operator_result(left_type, right_type, op); type_dict[context] = resulting_type; Debug.Assert(resulting_type != null && resulting_type != typeof(void)); return(resulting_type); }
private ObjectType VisitLogicalExpression(ParserRuleContext context, string op, ParserRuleContext left, ParserRuleContext right) { var leftType = left.Accept(this); var rightType = right.Accept(this); if (leftType == ObjectType.Boolean && rightType == ObjectType.Boolean) { return(ObjectType.Boolean); } _scriptEnvironmentBuilder.Errors.Add(new InvalidOperandsException(context, op, leftType, rightType)); return(ObjectType.Unknown); }
//public override ObjectType VisitArithmeticExpression(QuestScriptParser.ArithmeticExpressionContext context) private ObjectType VisitArithmeticExpression(ParserRuleContext context, ParserRuleContext op, ParserRuleContext left, ParserRuleContext right) { var leftType = left.Accept(this); var rightType = right.Accept(this); //if at least one is unknown, then we already have an error and can stop evaluating types if (leftType == ObjectType.Unknown || rightType == ObjectType.Unknown) { return(ObjectType.Unknown); } if (leftType == rightType) { return(leftType); } //we don't want to lose precision, thus any arithmetic expression with double operand becomes double too if (TypeUtil.IsNumeric(rightType) && TypeUtil.IsNumeric(leftType) && (leftType == ObjectType.Double || rightType == ObjectType.Double)) { return(ObjectType.Double); } if (TypeUtil.CanConvert(rightType, leftType)) { return(leftType); } if (TypeUtil.CanConvert(leftType, rightType)) { return(rightType); } _scriptEnvironmentBuilder.Errors.Add(new InvalidOperandsException(context, op.GetText(), leftType, rightType)); return(ObjectType.Unknown); }
private Lazy <object> VisitArithmeticExpression(ParserRuleContext context, ParserRuleContext op, ParserRuleContext left, ParserRuleContext right) { var expressionType = _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(context); if (!TypeUtil.IsNumeric(expressionType) && expressionType != ObjectType.String) { _scriptEnvironmentBuilder.Errors.Add( new InvalidOperandsException( context, op.GetText(), _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(left), _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(right))); return(new Lazy <object>(() => null)); } return(new Lazy <object>(() => { var leftValue = left.Accept(this).GetValueOrLazyValue(); var rightValue = right.Accept(this).GetValueOrLazyValue(); if (op.GetText() == "+") { //maybe we have string concatenation? if (leftValue is string leftStr) { return leftStr + rightValue; } if (rightValue is string rightStr) { return leftValue + rightStr; } } if (!(leftValue is int) && !(leftValue is double) || !(rightValue is int) && !(rightValue is double)) { return null; } bool TryConvertToNumber(object value, out double result) { result = 0; try { result = Convert.ToDouble(value); } catch (InvalidCastException e) { Errors.Add(new FailedToInferTypeException(context, left, e)); return false; } return true; } if (!TryConvertToNumber(leftValue, out var leftValueAsNumber)) { return null; } if (!TryConvertToNumber(rightValue, out var rightValueAsNumber)) { return null; } switch (op.GetText()) { case "+": return Cast(leftValueAsNumber + rightValueAsNumber, expressionType); case "-": return Cast(leftValueAsNumber - rightValueAsNumber, expressionType); case "/": if (Math.Abs(rightValueAsNumber) < 0.00000000001) //epsilon :) { var error = new DivisionByZeroException(context); Errors.Add(error); } var val = leftValueAsNumber / rightValueAsNumber; return Cast(val, expressionType); case "%": return Cast(leftValueAsNumber % rightValueAsNumber, expressionType); case "*": return Cast(leftValueAsNumber * rightValueAsNumber, expressionType); } //if not numeric and not string concatenation, nothing to do... return null; })); }