Esempio n. 1
0
        public override SucoExpression Optimize(SucoEnvironment env, int?[] givens)
        {
            var constants      = ElementType.CreateArray(Elements.Count);
            var expressions    = new SucoExpression[Elements.Count];
            var anyExpressions = false;

            for (var i = 0; i < Elements.Count; i++)
            {
                var opt = Elements[i].Optimize(env, givens);
                if (opt is SucoConstant c)
                {
                    constants.SetValue(c.Value, i);
                }
                else
                {
                    expressions[i] = opt;
                    anyExpressions = true;
                }
            }

            if (!anyExpressions)
            {
                return(new SucoConstant(StartIndex, EndIndex, Type, constants));
            }
            return(new SucoOptimizedArrayExpression(StartIndex, EndIndex, constants, expressions, Type));
        }
Esempio n. 2
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;
 }
Esempio n. 3
0
        private SucoExpression parseListComprehension(int?startIx = null, bool consumeCloseCurly = false)
        {
            var rStartIx = startIx ?? _ix;

            var            clauses  = new List <SucoListClause>();
            SucoExpression selector = null;

nextClause:
            var clauseStartIx = _ix;
            var flags = new Dictionary <string, SucoToken>();

nextFlag:
            foreach (var flag in _flags)
            {
                if (token(flag, out var flagToken))
                {
                    if (flags.ContainsKey(flag))
                    {
                        throw new SucoParseException($"Duplicate flag: “{flag}”.", flagToken, flags[flag]);
                    }
                    flags[flag] = flagToken;
                    goto nextFlag;
                }
            }
            var variableName = getToken();

            if (variableName.Type != SucoTokenType.Identifier)
            {
                throw new SucoParseException($"Expected variable name{_flags.Except(flags.Keys).ToArray().Select(s => $" or “{s}”").JoinString()}.", variableName);
            }
            _ix = variableName.EndIndex;

            var            conditions     = new List <SucoListCondition>();
            SucoExpression fromExpression = null;

            void commitClause(int endIndex)
            {
                SucoListClause clause;

                if (!flags.ContainsKey("1") && (clause = clauses.LastOrDefault(c => c.HasSingleton)) != null)
                {
                    throw new SucoParseException("A clause with a “1” flag cannot be followed by a clause without one.", clauseStartIx, endIndex, clause);
                }
                if (flags.ContainsKey("$") && fromExpression != null)
                {
                    throw new SucoParseException("A clause with a “$” flag cannot also have a “from” condition.", clauseStartIx, endIndex);
                }
                clauses.Add(new SucoListClause(clauseStartIx, endIndex, variableName.StringValue, flags.ContainsKey("$"), flags.ContainsKey("+"), flags.ContainsKey("1"), fromExpression, conditions));
            }

nextCondition:
            if (token(":", out var tok))
            {
                commitClause(tok.EndIndex);
                selector = parseExpression();
                goto done;
            }
            else if (token(",", out tok))
            {
                commitClause(tok.EndIndex);
                goto nextClause;
            }
            else if (token("(", out tok))
            {
                var innerExpr = parseExpression();
                if (!token(")"))
                {
                    throw new SucoParseException("Unmatched “(”: condition must end in “)”.", getToken(), tok);
                }
                conditions.Add(new SucoListExpressionCondition(tok.StartIndex, _ix, innerExpr));
                goto nextCondition;
            }

            foreach (var shc in new[] { "~", "<", ">", "^", "v", "←", "→", "↑", "↓" })
            {
                if (token(shc, out tok))
                {
                    conditions.Add(new SucoListShortcutCondition(tok.StartIndex, tok.EndIndex, shc));
                    goto nextCondition;
                }
            }

            tok = getToken();
            if (tok.Type == SucoTokenType.Identifier && tok.StringValue == "from")
            {
                if (fromExpression != null)
                {
                    throw new SucoParseException("Duplicate “from” condition.", tok, fromExpression);
                }

                _ix = tok.EndIndex;
                var tokVarName = getToken();
                if (tokVarName.Type == SucoTokenType.Identifier)
                {
                    fromExpression = new SucoIdentifierExpression(tokVarName.StartIndex, tokVarName.EndIndex, tokVarName.StringValue);
                    _ix            = tokVarName.EndIndex;
                }
                else
                {
                    if (!token("("))
                    {
                        throw new SucoParseException("“from” must be followed by either a variable name, or a parenthesized expression.", getToken(), tok);
                    }
                    fromExpression = parseExpression();
                    if (!token(")"))
                    {
                        throw new SucoParseException("Unmatched “(”: “from” expression must end in “)”.", getToken(), tok);
                    }
                }
                goto nextCondition;
            }
            if (tok.Type == SucoTokenType.Identifier)
            {
                conditions.Add(new SucoListShortcutCondition(tok.StartIndex, tok.EndIndex, tok.StringValue));
                _ix = tok.EndIndex;
                goto nextCondition;
            }

            commitClause(_ix);

done:
            if (selector == null)
            {
                if (clauses.Count != 1)
                {
                    throw new SucoParseException("List comprehensions with more than one clause must have a selector.", _ix, rStartIx);
                }
                selector = new SucoIdentifierExpression(_ix, _ix, clauses[0].VariableName);
            }
            if (consumeCloseCurly)
            {
                if (!token("}"))
                {
                    throw new SucoParseException("Unmatched “{”: list comprehension must be terminated with “}”.", _ix, rStartIx);
                }
            }
            return(new SucoListComprehensionExpression(rStartIx, _ix, clauses, selector));
        }
Esempio n. 4
0
 public SucoCallExpression(int startIndex, int endIndex, SucoExpression operand, SucoExpression[] arguments, SucoType type = null)
     : base(startIndex, endIndex, type)
 {
     Operand   = operand;
     Arguments = arguments;
 }
Esempio n. 5
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));
 }