public override SucoType GetBinaryOperatorType(BinaryOperator op, SucoType rightType, SucoContext context) => (op, rightType) switch { // Decimal op Decimal (BinaryOperator.Equal, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.NotEqual, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.LessThan, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.LessThanOrEqual, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.GreaterThan, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.GreaterThanOrEqual, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.Plus, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Minus, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Times, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Modulo, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Divide, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Power, SucoDecimalType) => SucoType.Decimal, // Decimal op Int (BinaryOperator.Equal, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.NotEqual, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.LessThan, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.LessThanOrEqual, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.GreaterThan, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.GreaterThanOrEqual, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.Plus, SucoIntegerType) => SucoType.Decimal, (BinaryOperator.Minus, SucoIntegerType) => SucoType.Decimal, (BinaryOperator.Times, SucoIntegerType) => SucoType.Decimal, (BinaryOperator.Modulo, SucoIntegerType) => SucoType.Decimal, (BinaryOperator.Divide, SucoIntegerType) => SucoType.Decimal, (BinaryOperator.Power, SucoIntegerType) => SucoType.Decimal, _ => base.GetBinaryOperatorType(op, rightType, context), };
public override SucoType GetBinaryOperatorType(BinaryOperator op, SucoType rightType, SucoContext context) => (op, rightType) switch { // Comparison with Int (BinaryOperator.Equal, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.NotEqual, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.LessThan, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.LessThanOrEqual, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.GreaterThan, SucoIntegerType) => SucoType.Boolean, (BinaryOperator.GreaterThanOrEqual, SucoIntegerType) => SucoType.Boolean, // Comparison with Decimal (BinaryOperator.Equal, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.NotEqual, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.LessThan, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.LessThanOrEqual, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.GreaterThan, SucoDecimalType) => SucoType.Boolean, (BinaryOperator.GreaterThanOrEqual, SucoDecimalType) => SucoType.Boolean, // Arithmetic with Int (BinaryOperator.Plus, SucoIntegerType) => SucoType.Integer, (BinaryOperator.Minus, SucoIntegerType) => SucoType.Integer, (BinaryOperator.Times, SucoIntegerType) => SucoType.Integer, (BinaryOperator.Modulo, SucoIntegerType) => SucoType.Integer, (BinaryOperator.Divide, SucoIntegerType) => context != SucoContext.Constraint ? SucoType.Decimal : throw new SucoTempCompileException("Suco does not allow the use of division in puzzle constraints. Rewrite the equation to use multiplication instead (for example: instead of a.value/b.value = 2, write a.value = 2*b.value)."), (BinaryOperator.Power, SucoIntegerType) => SucoType.Integer, // Arithmetic with Decimal (BinaryOperator.Plus, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Minus, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Times, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Modulo, SucoDecimalType) => SucoType.Decimal, (BinaryOperator.Power, SucoDecimalType) => SucoType.Decimal, _ => base.GetBinaryOperatorType(op, rightType, context), };
public override SucoType GetBinaryOperatorType(BinaryOperator op, SucoType rightType, SucoContext context) => (op, rightType) switch { (BinaryOperator.Equal, SucoBooleanType) => SucoType.Boolean, (BinaryOperator.NotEqual, SucoBooleanType) => SucoType.Boolean, (BinaryOperator.And, SucoBooleanType) => SucoType.Boolean, (BinaryOperator.Or, SucoBooleanType) => SucoType.Boolean, _ => base.GetBinaryOperatorType(op, rightType, context) };
public SucoListClause(int startIndex, int endIndex, string variableName, bool hasDollar, bool hasPlus, bool hasSingleton, SucoExpression fromExpression, List <SucoListCondition> conditions, SucoType varType = null) : base(startIndex, endIndex) { VariableName = variableName; HasDollar = hasDollar; HasPlus = hasPlus; HasSingleton = hasSingleton; FromExpression = fromExpression; Conditions = conditions; VariableType = varType; }
public override SucoListCondition DeduceTypes(SucoTypeEnvironment env, SucoContext context, SucoType elementType) { switch (Name) { case "first": case "last": case "before": case "after": case "~": break; case "^": case ">": case "v": case "<": case "↑": case "→": case "↓": case "←": case "diagonal": case "adjacent": case "orthogonal": case "above": case "right": case "below": case "left": case "samerow": case "samecol": case "samebox": case "topleft": case "topright": case "bottomleft": case "bottomright": case "lefttop": case "righttop": case "leftbottom": case "rightbottom": if (!elementType.Equals(SucoType.Cell)) { throw new SucoCompileException($"“{Name}” can only be used on lists of cells.", StartIndex, EndIndex); } break; default: throw new SucoCompileException($"Unknown shortcut condition: “{Name}”.", StartIndex, EndIndex); } return(this); }
public override bool Equals(SucoType other) => other is SucoListType list && list.ElementType.Equals(ElementType);
public SucoCallExpression(int startIndex, int endIndex, SucoExpression operand, SucoExpression[] arguments, SucoType type = null) : base(startIndex, endIndex, type) { Operand = operand; Arguments = arguments; }
public override object InterpretBinaryOperator(object left, BinaryOperator @operator, SucoType rightType, object right) => (@operator, rightType) switch { // Comparison with Int (BinaryOperator.Equal, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a == b), (BinaryOperator.NotEqual, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a != b), (BinaryOperator.LessThan, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a < b), (BinaryOperator.LessThanOrEqual, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a <= b), (BinaryOperator.GreaterThan, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a > b), (BinaryOperator.GreaterThanOrEqual, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a >= b), // Comparison with Decimal (BinaryOperator.Equal, SucoDecimalType) => (int)left == (double)right, (BinaryOperator.NotEqual, SucoDecimalType) => (int)left != (double)right, (BinaryOperator.LessThan, SucoDecimalType) => (int)left <(double)right, (BinaryOperator.LessThanOrEqual, SucoDecimalType) => (int)left <= (double)right, (BinaryOperator.GreaterThan, SucoDecimalType) => (int)left> (double) right, (BinaryOperator.GreaterThanOrEqual, SucoDecimalType) => (int)left >= (double)right, // Integer arithmetic (BinaryOperator.Plus, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a + b), (BinaryOperator.Minus, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a - b), (BinaryOperator.Times, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => a * b), (BinaryOperator.Modulo, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => (a % b + b) % b), (BinaryOperator.Divide, SucoIntegerType) => (double)(int)left / (int)right, (BinaryOperator.Power, SucoIntegerType) => op((int?)left, (int?)right, (a, b) => (int)BigInteger.Pow(a, b)), // Decimal arithmetic (BinaryOperator.Plus, SucoDecimalType) => (int)left + (double)right, (BinaryOperator.Minus, SucoDecimalType) => (int)left - (double)right, (BinaryOperator.Times, SucoDecimalType) => (int)left * (double)right, (BinaryOperator.Modulo, SucoDecimalType) => ((int)left % (double)right + (double)right) % (double)right, (BinaryOperator.Power, SucoDecimalType) => Math.Pow((int)left, (double)right), _ => base.InterpretBinaryOperator(left, @operator, rightType, right), };
public SucoListComprehensionExpression(int startIndex, int endIndex, List <SucoListClause> clauses, SucoExpression selector, SucoType type = null) : base(startIndex, endIndex, type) { Clauses = clauses ?? throw new ArgumentNullException(nameof(clauses)); Selector = selector ?? throw new ArgumentNullException(nameof(selector)); }
public static bool IsValidCode(string source, SucoTypeEnvironment env, SucoContext context, SucoType expectedResultType, out string error) { try { ParseCode(source, env, context, expectedResultType); error = null; return(true); } catch (SucoCompileException sce) { error = sce.Message; return(false); } catch (SucoParseException spe) { error = spe.Message; return(false); } }
public SucoVariable(string name, SucoType type) { Name = name; Type = type; }
public override object InterpretBinaryOperator(object left, BinaryOperator op, SucoType rightType, object right) => (op, rightType) switch { // Decimal op Decimal (BinaryOperator.Equal, SucoDecimalType) => (double)left == (double)right, (BinaryOperator.NotEqual, SucoDecimalType) => (double)left != (double)right, (BinaryOperator.LessThan, SucoDecimalType) => (double)left <(double)right, (BinaryOperator.LessThanOrEqual, SucoDecimalType) => (double)left <= (double)right, (BinaryOperator.GreaterThan, SucoDecimalType) => (double)left> (double) right, (BinaryOperator.GreaterThanOrEqual, SucoDecimalType) => (double)left >= (double)right, (BinaryOperator.Plus, SucoDecimalType) => (double)left + (double)right, (BinaryOperator.Minus, SucoDecimalType) => (double)left - (double)right, (BinaryOperator.Times, SucoDecimalType) => (double)left * (double)right, (BinaryOperator.Modulo, SucoDecimalType) => ((double)left % (double)right + (double)right) % (double)right, (BinaryOperator.Divide, SucoDecimalType) => (double)left / (double)right, (BinaryOperator.Power, SucoDecimalType) => Math.Pow((double)left, (double)right), // Decimal op Int (BinaryOperator.Equal, SucoIntegerType) => (double)left == (int)right, (BinaryOperator.NotEqual, SucoIntegerType) => (double)left != (int)right, (BinaryOperator.LessThan, SucoIntegerType) => (double)left <(int)right, (BinaryOperator.LessThanOrEqual, SucoIntegerType) => (double)left <= (int)right, (BinaryOperator.GreaterThan, SucoIntegerType) => (double)left> (int) right, (BinaryOperator.GreaterThanOrEqual, SucoIntegerType) => (double)left >= (int)right, (BinaryOperator.Plus, SucoIntegerType) => (double)left + (int)right, (BinaryOperator.Minus, SucoIntegerType) => (double)left - (int)right, (BinaryOperator.Times, SucoIntegerType) => (double)left * (int)right, (BinaryOperator.Modulo, SucoIntegerType) => ((double)left % (int)right + (int)right) % (int)right, (BinaryOperator.Divide, SucoIntegerType) => (double)left / (int)right, (BinaryOperator.Power, SucoIntegerType) => Math.Pow((double)left, (int)right), _ => base.InterpretBinaryOperator(left, op, rightType, right), };
public override bool Equals(SucoType other) => other is SucoDecimalType;
public override bool Equals(SucoType other) => other is SucoCellType;
public override bool Equals(SucoType other) => other is SucoStringType;
public SucoArrayExpression(int startIndex, int endIndex, List <SucoExpression> elements, SucoType type = null) : base(startIndex, endIndex, type) { Elements = elements; }
public SucoStringLiteralExpression(int startIndex, int endIndex, SucoStringLiteralPiece[] pieces, SucoType type = null) : base(startIndex, endIndex, type) { Pieces = pieces; }
public SucoExpression ImplicitlyConvertTo(SucoType type) => Type.Equals(type) ? this : Type.ImplicitlyConvertibleTo(type) ? new SucoImplicitConversionExpression(StartIndex, EndIndex, this, type) : throw new InvalidOperationException("Unexpected implicit conversion. Call Type.ImplicitlyConvertibleTo first to ensure convertibility.");
public static SucoExpression ParseCode(string source, SucoTypeEnvironment env, SucoContext context, SucoType expectedResultType = null) { if (source == null) { throw new ArgumentNullException(nameof(source)); } try { // Try parsing as a standalone expression (e.g. “cells.unique”). var parser = new SucoParser(source, context); var ret = parser.parseExpression(); parser.EnforceEof(); ret = ret.DeduceTypes(env, context); if (expectedResultType != null && !ret.Type.ImplicitlyConvertibleTo(expectedResultType)) { throw new SucoParseException($"The expression is of type “{ret.Type}”, which is not implicitly convertible to the required type, “{expectedResultType}”.", ret.StartIndex, ret.EndIndex); } return(expectedResultType == null ? ret : ret.ImplicitlyConvertTo(expectedResultType)); } catch (SucoParseException pe1) { try { // Try parsing as a list comprehension (e.g. “a: a.odd”). var parser = new SucoParser(source, context); var ret = parser.parseListComprehension(); parser.EnforceEof(); ret = ret.DeduceTypes(env, context); if (expectedResultType != null && !ret.Type.ImplicitlyConvertibleTo(expectedResultType)) { throw new SucoParseException($"The expression is of type “{ret.Type}”, which is not implicitly convertible to the required type, “{expectedResultType}”.", ret.StartIndex, ret.EndIndex); } return(expectedResultType == null ? ret : ret.ImplicitlyConvertTo(expectedResultType)); } catch (SucoParseException pe2) when(pe2.StartIndex <= pe1.StartIndex) { } throw; } }
public SucoOptimizedArrayExpression(int startIndex, int endIndex, Array constants, SucoExpression[] expressions, SucoType type) : base(startIndex, endIndex, type) { Constants = constants; Expressions = expressions; }
public SucoExpression(int startIndex, int endIndex, SucoType type = null) : base(startIndex, endIndex) { Type = type; }
public override object InterpretBinaryOperator(object left, BinaryOperator @operator, SucoType rightType, object right) => (@operator, rightType) switch { (BinaryOperator.Equal, SucoBooleanType) => op((bool?)left, (bool?)right, (a, b) => a == b), (BinaryOperator.NotEqual, SucoBooleanType) => op((bool?)left, (bool?)right, (a, b) => a != b), (BinaryOperator.And, SucoBooleanType) => (bool?)left == false || (bool?)right == false ? false : left == null || right == null ? null : true, (BinaryOperator.Or, SucoBooleanType) => (bool?)left == true || (bool?)right == true ? true : left == null || right == null ? null : false, _ => base.InterpretBinaryOperator(left, @operator, rightType, right) };
public override bool Equals(SucoType other) => other is SucoBooleanType;
public SucoListType(SucoType elementType) { ElementType = elementType; }
public override bool Equals(SucoType other) => other is SucoIntegerType;
public override bool Equals(SucoType other) => other is SucoEnumType e && e.Names.SequenceEqual(Names);