Пример #1
0
        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),
        };
Пример #2
0
        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),
        };
Пример #3
0
 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)
 };
Пример #4
0
 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;
 }
Пример #5
0
        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);
        }
Пример #6
0
 public override bool Equals(SucoType other) => other is SucoListType list && list.ElementType.Equals(ElementType);
Пример #7
0
 public SucoCallExpression(int startIndex, int endIndex, SucoExpression operand, SucoExpression[] arguments, SucoType type = null)
     : base(startIndex, endIndex, type)
 {
     Operand   = operand;
     Arguments = arguments;
 }
Пример #8
0
        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),
        };
Пример #9
0
 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));
 }
Пример #10
0
 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);
     }
 }
Пример #11
0
 public SucoVariable(string name, SucoType type)
 {
     Name = name;
     Type = type;
 }
Пример #12
0
        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),
        };
Пример #13
0
 public override bool Equals(SucoType other) => other is SucoDecimalType;
Пример #14
0
 public override bool Equals(SucoType other) => other is SucoCellType;
Пример #15
0
 public override bool Equals(SucoType other) => other is SucoStringType;
Пример #16
0
 public SucoArrayExpression(int startIndex, int endIndex, List <SucoExpression> elements, SucoType type = null)
     : base(startIndex, endIndex, type)
 {
     Elements = elements;
 }
Пример #17
0
 public SucoStringLiteralExpression(int startIndex, int endIndex, SucoStringLiteralPiece[] pieces, SucoType type = null)
     : base(startIndex, endIndex, type)
 {
     Pieces = pieces;
 }
Пример #18
0
 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.");
Пример #19
0
        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;
            }
        }
Пример #20
0
 public SucoOptimizedArrayExpression(int startIndex, int endIndex, Array constants, SucoExpression[] expressions, SucoType type)
     : base(startIndex, endIndex, type)
 {
     Constants   = constants;
     Expressions = expressions;
 }
Пример #21
0
 public SucoExpression(int startIndex, int endIndex, SucoType type = null)
     : base(startIndex, endIndex)
 {
     Type = type;
 }
Пример #22
0
 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)
 };
Пример #23
0
 public override bool Equals(SucoType other) => other is SucoBooleanType;
Пример #24
0
 public SucoListType(SucoType elementType)
 {
     ElementType = elementType;
 }
Пример #25
0
 public override bool Equals(SucoType other) => other is SucoIntegerType;
Пример #26
0
 public override bool Equals(SucoType other) => other is SucoEnumType e && e.Names.SequenceEqual(Names);