예제 #1
0
        protected override SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context)
        {
            var newEnv       = env;
            var newClauses   = new List <SucoListClause>();
            var anySingleton = false;

            foreach (var clause in Clauses)
            {
                var newFromExpression = clause.FromExpression?.DeduceTypes(newEnv, context);

                // Deduce the type of the iterator variable
                SucoType collectionType;
                if (newFromExpression != null)
                {
                    collectionType = newFromExpression.Type;
                }
                else if (clause.HasDollar)
                {
                    collectionType = SucoType.Cell.List();
                }
                else
                {
                    try
                    {
                        collectionType = env.GetVariableType("cells");
                    }
                    catch (SucoTempCompileException tc)
                    {
                        throw new SucoCompileException(tc.Message, clause.StartIndex, clause.EndIndex);
                    }
                }

                if (collectionType is not SucoListType {
                    ElementType: SucoType elementType
                })
예제 #2
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);
        }
예제 #3
0
        protected override SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context)
        {
            if (Elements.Count == 0)
            {
                throw new SucoCompileException("Empty array literals are not currently supported.", StartIndex, EndIndex);
            }
            var newElements = Elements.Select(e => e.DeduceTypes(env, context)).ToList();

            for (var i = 0; i < newElements.Count; i++)
            {
                if (newElements.All(e => e.Type.ImplicitlyConvertibleTo(newElements[i].Type)))
                {
                    return(new SucoArrayExpression(StartIndex, EndIndex, newElements.Select(e => e.ImplicitlyConvertTo(newElements[i].Type)).ToList(), newElements[i].Type.List()));
                }
            }
            throw new SucoCompileException("This array contains elements that are not compatible with one another.", StartIndex, EndIndex);
        }
예제 #4
0
        protected override SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context)
        {
            var newPieces = Pieces.Select(p =>
            {
                if (p is not SucoStringLiteralPieceExpression expr)
                {
                    return(p);
                }
                var typedExpr = expr.Expression.DeduceTypes(env, context);
                if (!typedExpr.Type.ImplicitlyConvertibleTo(SucoType.String))
                {
                    throw new SucoCompileException($"Expression interpolated into a string literal is of type “{typedExpr.Type}”, which not implicitly convertible to string.", expr.Expression.StartIndex, expr.Expression.EndIndex);
                }
                return(typedExpr.ImplicitlyConvertTo(SucoType.String));
            }).ToArray();

            return(new SucoStringLiteralExpression(StartIndex, EndIndex, newPieces, SucoType.String));
        }
예제 #5
0
파일: SucoParser.cs 프로젝트: Timwi/Zinga
 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);
     }
 }
예제 #6
0
파일: SucoParser.cs 프로젝트: Timwi/Zinga
        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;
            }
        }
예제 #7
0
        public SucoExpression DeduceTypes(SucoTypeEnvironment env, SucoContext context)
        {
            var result = deduceTypes(env, context);

            switch (context)
            {
            case SucoContext.Constraint:
                if (result.Type is SucoDecimalType)
                {
                    throw new SucoCompileException("You cannot use decimal numbers in a puzzle constraint.", StartIndex, EndIndex);
                }
                if (result.Type is SucoStringType)
                {
                    throw new SucoCompileException("You cannot use strings in a puzzle constraint.", StartIndex, EndIndex);
                }
                break;

            case SucoContext.Svg:
                break;
            }
            return(result);
        }
예제 #8
0
        protected override SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context)
        {
            try
            {
                var operand = Operand.DeduceTypes(env, context);
                if (operand.Type is not SucoFunctionType fnc)
                {
                    throw new SucoCompileException($"“{operand.Type}” is not a function type.", operand.StartIndex, operand.EndIndex);
                }

                var newArguments = Arguments.Select(arg => arg.DeduceTypes(env, context)).ToArray();
                var(parameterTypes, returnType) = fnc.Resolve(newArguments.Select(a => a.Type).ToArray());
                for (var i = 0; i < newArguments.Length; i++)
                {
                    newArguments[i] = newArguments[i].ImplicitlyConvertTo(parameterTypes[i]);
                }
                return(new SucoCallExpression(StartIndex, EndIndex, operand, newArguments, returnType));
            }
            catch (SucoFunctionResolutionException re)
            {
                throw new SucoCompileException(re.Message, StartIndex, EndIndex);
            }
        }
예제 #9
0
 protected abstract SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context);
예제 #10
0
 protected override SucoExpression deduceTypes(SucoTypeEnvironment env, SucoContext context) => this;