public static IExpression CreateEqualityComparisonOperator( IValueGetter arg1, IValueGetter arg2, OperatorToken operatorToken) { Type argType; Type arg1Type = arg1.GetValueType(); Type arg2Type = arg2.GetValueType(); if (arg1Type == arg2Type) { argType = arg1Type; } else if (arg1Type.AssignableFromType(arg2Type)) { argType = arg1Type; } else if (arg2Type.AssignableFromType(arg1Type)) { argType = arg2Type; } else { throw new ScriptParsingException( source: operatorToken, message: $"Incompatible Types for {operatorToken.operatorType} operator: {arg1Type.Name} and {arg2Type.Name}"); } //Constant case if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2) { object value1 = litArg1.GetAs <object>(); object value2 = litArg2.GetAs <object>(); if (argType != arg1Type) { value1 = Convert.ChangeType(value1, argType); } if (argType != arg2Type) { value2 = Convert.ChangeType(value2, argType); } switch (operatorToken.operatorType) { case Operator.IsEqualTo: return(new LiteralToken <bool>(operatorToken, value1.Equals(value2))); case Operator.IsNotEqualTo: return(new LiteralToken <bool>(operatorToken, !value1.Equals(value2))); default: throw new ArgumentException($"Unexpected Operator: {operatorToken.operatorType}"); } } return(new EqualityCompairsonOperation(arg1, arg2, argType, operatorToken.operatorType)); }
public static IExpression CreateBinaryNumericalOperation( IValueGetter arg1, IValueGetter arg2, OperatorToken operatorToken) { Type arg1Type = arg1.GetValueType(); Type arg2Type = arg2.GetValueType(); Type valueType; if (!(arg1Type == typeof(double) || arg1Type == typeof(int))) { throw new ScriptParsingException( source: operatorToken, message: $"Left side of operator {operatorToken.operatorType} not of expected type int or bool: {arg1.GetValueType().Name}"); } if (!(arg2Type == typeof(double) || arg2Type == typeof(int))) { throw new ScriptParsingException( source: operatorToken, message: $"Right side of operator {operatorToken.operatorType} not of expected type int or bool: {arg2.GetValueType().Name}"); } if (arg1Type == arg2Type) { valueType = arg1Type; } else { valueType = typeof(double); } //Constant case if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2) { if (valueType == typeof(int)) { return(new LiteralToken <int>( operatorToken, IntOperator <int>(litArg1.GetAs <int>(), litArg2.GetAs <int>(), operatorToken.operatorType, valueType))); } else { return(new LiteralToken <double>( operatorToken, DoubleOperator <double>(litArg1.GetAs <double>(), litArg2.GetAs <double>(), operatorToken.operatorType, valueType))); } } return(new BinaryNumericalOperation(arg1, arg2, valueType, operatorToken.operatorType)); }
public static IExpression CreateNotOperation( IValueGetter arg, OperatorToken operatorToken) { if (arg.GetValueType() != typeof(bool)) { throw new ScriptParsingException( source: operatorToken, message: $"Argument of Operator {operatorToken} is not boolean: type {arg.GetValueType().Name}."); } if (arg is LiteralToken litArg) { return(new LiteralToken <bool>(operatorToken, !litArg.GetAs <bool>())); } return(new NotOperation(arg)); }
public static IExpression CreateComparisonOperation( IValueGetter arg1, IValueGetter arg2, OperatorToken operatorToken) { if (!(arg1.GetValueType() == typeof(double) || arg1.GetValueType() == typeof(int))) { throw new ScriptParsingException( source: operatorToken, message: $"Left side of operator {operatorToken.operatorType} has incompatible type: {arg1.GetValueType().Name}"); } if (!(arg2.GetValueType() == typeof(double) || arg2.GetValueType() == typeof(int))) { throw new ScriptParsingException( source: operatorToken, message: $"Right side of operator {operatorToken.operatorType} has incompatible type: {arg2.GetValueType().Name}"); } //Constant case if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2) { switch (operatorToken.operatorType) { case Operator.IsGreaterThan: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() > litArg2.GetAs <double>())); case Operator.IsGreaterThanOrEqualTo: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() >= litArg2.GetAs <double>())); case Operator.IsLessThan: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() < litArg2.GetAs <double>())); case Operator.IsLessThanOrEqualTo: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() <= litArg2.GetAs <double>())); default: throw new ArgumentException($"Unexpected Operator {operatorToken.operatorType}"); } } return(new ComparisonOperation(arg1, arg2, operatorToken.operatorType)); }
public TernaryOperation( IValueGetter condition, IValueGetter arg1, IValueGetter arg2, OperatorToken operatorToken) { Type arg1Type = arg1.GetValueType(); Type arg2Type = arg2.GetValueType(); if (condition.GetValueType() != typeof(bool)) { throw new ScriptParsingException( source: operatorToken, message: $"Condition of Ternary Operator must be a boolean value: type {condition.GetValueType()}."); } if (arg1Type == arg2Type) { valueType = arg1Type; } else if ((arg1Type == typeof(int) || arg1Type == typeof(double)) && (arg2Type == typeof(int) || arg2Type == typeof(double))) { valueType = typeof(double); } else { throw new ScriptParsingException( source: operatorToken, message: $"Incompatible argments in Ternary operator: {arg1Type.Name} vs {arg2Type.Name}"); } this.condition = condition; this.arg1 = arg1; this.arg2 = arg2; }
private static void ReduceAssignmentOperators(List <ParsingUnit> units) { for (int i = 0; i < units.Count; i++) { if (units[i].OperatorType == Operator.Assignment || units[i].OperatorType == Operator.PlusEquals || units[i].OperatorType == Operator.MinusEquals || units[i].OperatorType == Operator.TimesEquals || units[i].OperatorType == Operator.DivideEquals || units[i].OperatorType == Operator.PowerEquals || units[i].OperatorType == Operator.ModuloEquals || units[i].OperatorType == Operator.AndEquals || units[i].OperatorType == Operator.OrEquals) { if (i == 0) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression began with a {units[i].OperatorType} operator: {units[i].FirstToken}"); } if (i == units.Count - 1) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression ended with a {units[i].OperatorType} operator: {units[i].FirstToken}"); } if (units[i - 1].AsValue == null) { throw new ScriptParsingException( source: units[i - 1].FirstToken, message: $"Expression before {units[i].OperatorType} operator must be modifiable: {units[i - 1].FirstToken}"); } if (units[i + 1].AsValueGetter == null) { throw new ScriptParsingException( source: units[i + 1].FirstToken, message: $"Expression after {units[i].OperatorType} operator must have a value: {units[i + 1].FirstToken}"); } OperatorToken operatorToken = units[i].FirstToken as OperatorToken; //Cache Value and remove Right value and operator IValueGetter value = units[i + 1].AsValueGetter; units.RemoveAt(i + 1); units.RemoveAt(i); //adjust our current position i--; //Swap the ParsingUnit for the calculated value switch (operatorToken.operatorType) { case Operator.Assignment: units[i] = new ParsedValuedUnit( value: new AssignmentOperation( assignee: units[i].AsValue, value: value, source: operatorToken), firstToken: units[i].FirstToken); break; case Operator.PlusEquals: units[i] = new ParsedValuedUnit( value: new PlusEqualsOperation( assignee: units[i].AsValue, value: value, source: operatorToken), firstToken: units[i].FirstToken); break; case Operator.MinusEquals: case Operator.TimesEquals: case Operator.DivideEquals: case Operator.PowerEquals: case Operator.ModuloEquals: //Handle Numerical Operators units[i] = new ParsedValuedUnit( value: new NumericalInPlaceOperation( assignee: units[i].AsValue, value: value, operatorType: operatorToken.operatorType, source: operatorToken), firstToken: units[i].FirstToken); break; case Operator.AndEquals: case Operator.OrEquals: units[i] = new ParsedValuedUnit( value: new BooleanInPlaceOperation( assignee: units[i].AsValue, value: value, operatorType: operatorToken.operatorType, source: operatorToken), firstToken: units[i].FirstToken); break; default: throw new ArgumentException($"Unexpected Operator: {operatorToken.operatorType}"); } } } }
private static void ReduceTernaryOperator(List <ParsingUnit> units) { for (int i = 0; i < units.Count; i++) { if (units[i].OperatorType == Operator.Ternary) { if (i == 0) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression began with a {units[i].OperatorType} operator: {units[i].FirstToken}"); } if (i >= units.Count - 2) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression with a {units[i].OperatorType} operator didn't contain enought arguments: {units[i].FirstToken}"); } if (units[i - 1].AsValueGetter == null) { throw new ScriptParsingException( source: units[i - 1].FirstToken, message: $"Unexpected token before {units[i].OperatorType} operator: {units[i - 1].FirstToken}"); } if (units[i + 1].AsValueGetter == null) { throw new ScriptParsingException( source: units[i + 1].FirstToken, message: $"Unexpected token after {units[i].OperatorType} operator: {units[i + 1].FirstToken}"); } if (units[i + 2].AsValueGetter == null) { throw new ScriptParsingException( source: units[i + 1].FirstToken, message: $"Unexpected token for second arguemnt of {units[i].OperatorType} operator: {units[i + 2].FirstToken}"); } OperatorToken operatorToken = units[i].FirstToken as OperatorToken; //Cache Value and remove Right value and operator IValueGetter arg1Value = units[i + 1].AsValueGetter; IValueGetter arg2Value = units[i + 2].AsValueGetter; units.RemoveAt(i + 2); units.RemoveAt(i + 1); units.RemoveAt(i); //adjust our current position i--; //Swap the ParsingUnit for the calculated value units[i] = new ParsedValuedUnit( value: new TernaryOperation( condition: units[i].AsValueGetter, arg1: arg1Value, arg2: arg2Value, operatorToken: operatorToken), firstToken: units[i].FirstToken); } } }
private static void ReduceBinaryOperator( Operator op, List <ParsingUnit> units) { for (int i = 0; i < units.Count; i++) { if (units[i].OperatorType == op) { if (i == 0) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression began with a {units[i].OperatorType} operator: {units[i].FirstToken}"); } if (i == units.Count - 1) { throw new ScriptParsingException( source: units[i].FirstToken, message: $"Expression ended with a {units[i].OperatorType} operator: {units[i].FirstToken}"); } if (units[i - 1].AsValueGetter == null) { throw new ScriptParsingException( source: units[i - 1].FirstToken, message: $"Unexpected token before {units[i].OperatorType} operator: {units[i - 1].FirstToken}"); } if (units[i + 1].AsValueGetter == null) { throw new ScriptParsingException( source: units[i + 1].FirstToken, message: $"Unexpected token after {units[i].OperatorType} operator: {units[i + 1].FirstToken}"); } OperatorToken operatorToken = units[i].FirstToken as OperatorToken; //Cache Value and remove Right value and operator IValueGetter arg2Value = units[i + 1].AsValueGetter; units.RemoveAt(i + 1); units.RemoveAt(i); //adjust our current position i--; //Swap the ParsingUnit for the calculated value switch (op) { case Operator.Plus: if (units[i].AsValueGetter.GetValueType() == typeof(string) || arg2Value.GetValueType() == typeof(string)) { //Handle String Concatenation units[i] = new ParsedValuedUnit( value: ConcatenateOperator.CreateConcatenateOperator( arg1: units[i].AsValueGetter, arg2: arg2Value), firstToken: units[i].FirstToken); break; } //Handle like addition goto case Operator.Minus; case Operator.Minus: case Operator.Times: case Operator.Divide: case Operator.Power: case Operator.Modulo: //Handle Numerical Operators units[i] = new ParsedValuedUnit( value: BinaryNumericalOperation.CreateBinaryNumericalOperation( arg1: units[i].AsValueGetter, arg2: arg2Value, operatorToken: operatorToken), firstToken: units[i].FirstToken); break; case Operator.IsEqualTo: case Operator.IsNotEqualTo: units[i] = new ParsedValuedUnit( value: EqualityCompairsonOperation.CreateEqualityComparisonOperator( arg1: units[i].AsValueGetter, arg2: arg2Value, operatorToken: operatorToken), firstToken: units[i].FirstToken); break; case Operator.IsGreaterThan: case Operator.IsGreaterThanOrEqualTo: case Operator.IsLessThan: case Operator.IsLessThanOrEqualTo: units[i] = new ParsedValuedUnit( value: ComparisonOperation.CreateComparisonOperation( arg1: units[i].AsValueGetter, arg2: arg2Value, operatorToken: operatorToken), firstToken: units[i].FirstToken); break; case Operator.And: case Operator.Or: units[i] = new ParsedValuedUnit( value: BinaryBoolOperation.CreateBinaryBoolOperator( arg1: units[i].AsValueGetter, arg2: arg2Value, operatorToken: operatorToken), firstToken: units[i].FirstToken); break; default: throw new ArgumentException($"Unexpected Operator: {op}"); } } } }
private static void HandleNextOperator( OperatorToken opToken, List <ParsingUnit> units, IEnumerator <Token> tokens, CompilationContext context) { switch (opToken.operatorType) { case Operator.Assignment: case Operator.PlusEquals: case Operator.MinusEquals: case Operator.TimesEquals: case Operator.DivideEquals: case Operator.PowerEquals: case Operator.ModuloEquals: case Operator.AndEquals: case Operator.OrEquals: case Operator.Plus: case Operator.Minus: case Operator.Times: case Operator.Divide: case Operator.Power: case Operator.Modulo: case Operator.CastDouble: case Operator.CastInteger: case Operator.Increment: case Operator.Decrement: case Operator.Not: case Operator.IsEqualTo: case Operator.IsNotEqualTo: case Operator.IsGreaterThan: case Operator.IsGreaterThanOrEqualTo: case Operator.IsLessThan: case Operator.IsLessThanOrEqualTo: case Operator.And: case Operator.Or: case Operator.Negate: //Add and continue units.Add(new TokenUnit(opToken)); tokens.CautiousAdvance(); break; case Operator.Ternary: //Add the ternary Operator units.Add(new TokenUnit(opToken)); tokens.CautiousAdvance(); //Add the first expected expression Token firstToken = tokens.Current; units.Add(new ParsedValuedUnit( value: ParseNextExpression(tokens, context), firstToken: firstToken)); //Colon tokens.AssertAndSkip(Separator.Colon); //Add the second expected expression firstToken = tokens.Current; units.Add(new ParsedValuedUnit( value: ParseNextExpression(tokens, context), firstToken: firstToken)); break; case Operator.MemberAccess: tokens.CautiousAdvance(); IdentifierToken nameToken = tokens.GetTokenAndAdvance <IdentifierToken>(); if (tokens.TestWithoutSkipping(Separator.OpenParen)) { //Method units.Add(new MemberAccessUnit( identifier: nameToken.identifier, args: ParseArguments(tokens, context), firstToken: opToken)); } else { //Value units.Add(new MemberAccessUnit( identifier: nameToken.identifier, args: null, firstToken: opToken)); } break; case Operator.AmbiguousMinus: default: throw new ArgumentException($"Unsupported Operator: {opToken.operatorType}"); } }