Example #1
0
        public static int Match(Value left, Value right, Namespace ns, bool usePopper = true)
        {
            using (var popper = new NamespacePopper(ns, "case match"))
            {
                popper.Push();
                Runtime.State.SetLocal(Runtime.State.DefaultParameterNames.ValueVariable, left);
                if (left.ID == right.ID)
                {
                    return(0);
                }
                if (right.Type == ValueType.Any)
                {
                    return(0);
                }
                if (right.Type == ValueType.Placeholder)
                {
                    Runtime.State.SetLocal(right.Text, left);
                    return(0);
                }
                if (right.IsArray && left.IsArray)
                {
                    var leftArray  = (Array)left.SourceArray;
                    var rightArray = (Array)right.SourceArray;
                    int match      = leftArray.Match(rightArray);
                    return(match);
                }

                var obj1 = left as Object;
                if (obj1 != null)
                {
                    var obj2 = right as Object;
                    if (obj2 != null)
                    {
                        var chains   = new Hash <string, MessageChain>();
                        var bindings = new Hash <string, Value>
                        {
                            DefaultValue = ""
                        };
                        var repeating = false;
                        int comparison;
                        while (true)
                        {
                            comparison = obj1.Compare(obj2, chains, new MessageChain(), bindings, ref repeating);
                            if (comparison == 0)
                            {
                                foreach (KeyValuePair <string, MessageChain> item in chains)
                                {
                                    Runtime.State[item.Key, true] = item.Value.Invoke(obj1);
                                }
                                return(comparison);
                            }
                            if (!repeating)
                            {
                                break;
                            }
                        }
                        return(comparison);
                    }
                    var cls = right as Class;
                    if (cls != null)
                    {
                        return(obj1.Class.ClassName.CompareTo(cls.ClassName));
                    }
                }
                var pattern = right as Pattern;
                if (pattern != null)
                {
                    return(pattern.IsMatch(left.Text) ? 0 : 1);
                }
                var obj = right as Object;
                if (obj != null)
                {
                    Class cls   = obj.Class;
                    Value value = CompareClass(cls, left);
                    if (value == null || value.Type == ValueType.Nil)
                    {
                        return(1);
                    }
                    Runtime.Assert(value.Type == ValueType.Object, "Case", "extract must return an Object or a nil");
                    return(Match(value, obj, ns, false));
                }
                return(left.Compare(right));
            }
        }
Example #2
0
 public override int Compare(Value value) => source.Compare(value);
Example #3
0
 public override int Compare(Value value) => innerValue.Compare(value);
Example #4
0
        public static bool Match(Value left, Value right, bool required, Block condition, string bindingName = "", bool assigning = false)
        {
            if (left is IMatch matching)
            {
                return(returnMatched(matching.Match(right), required, condition));
            }

            if (right is BoundValue boundValue)
            {
                var fieldName  = boundValue.Name;
                var realResult = Match(left, boundValue.InnerValue, required, condition, fieldName);
                if (realResult && !(boundValue.InnerValue is Class))
                {
                    Regions.SetBinding(fieldName, left, assigning);
                }
                return(realResult);
            }

            if (right is Block block)
            {
                right = block.Evaluate();
            }

            if (left is Some leftSome)
            {
                (var someMatched, var cargoName, var cargo) = leftSome.Match(right);
                if (someMatched && cargoName != "_")
                {
                    Regions.SetBinding(cargoName, cargo, assigning);
                }
                return(returnMatched(someMatched, required, condition));
            }

            if (left.Type == ValueType.None && right.Type == ValueType.None)
            {
                return(returnMatched(true, required, condition));
            }

            if (left is Failure leftFailure)
            {
                (var someMatched, var messageName, var message) = leftFailure.Match(right);
                if (someMatched && messageName != "_")
                {
                    Regions.SetBinding(messageName, message, assigning);
                }
                return(returnMatched(someMatched, required, condition));
            }

            if (left is List leftList)
            {
                if (right is List rightList)
                {
                    return(returnMatched(leftList.Match(rightList), required, condition));
                }
                if (right.IsNil)
                {
                    return(returnMatched(false, required, condition));
                }
            }

            bool leftWasAnObject;
            bool matched;

            if (right.Type != ValueType.Any && right.Type != ValueType.Placeholder)
            {
                matched = matchToLeftObject(left, right, required, condition, out leftWasAnObject, bindingName, assigning);
                if (leftWasAnObject)
                {
                    return(returnMatched(matched, required, condition));
                }
            }

            if (right is Object rightObject)
            {
                var rightClass = rightObject.Class;
                if (rightClass.RespondsTo("match"))
                {
                    left = rightClass.StaticObject.SendToSelf("match", left);
                    if (left?.IsNil ?? true)
                    {
                        return(returnMatched(false, required, condition));
                    }

                    matched = matchToLeftObject(left, right, required, condition, out leftWasAnObject, bindingName, assigning);
                    if (leftWasAnObject)
                    {
                        return(returnMatched(matched, required, condition));
                    }
                }
            }

            if (left is Record leftRecord && right is Record rightRecord)
            {
                return(returnMatched(leftRecord.Match(rightRecord, required), required, condition));
            }

            if (right is AutoInvoker autoInvoker)
            {
                right = autoInvoker.Resolve();
            }
            if (left.IsNil || right.IsNil)
            {
                return(returnMatched(false, required, condition));
            }

            if (right is Alternation alternation)
            {
                alternation.Reset();
                while (true)
                {
                    var value = alternation.Dequeue();
                    if (value.IsNil)
                    {
                        return(returnMatched(false, required, condition));
                    }

                    var result = Match(left, value, required, condition);
                    if (result)
                    {
                        return(returnMatched(true, required, condition));
                    }
                }
            }

            if (left.ID == right.ID)
            {
                return(returnMatched(true, required, condition));
            }
            if (left.Type == ValueType.String && right.Type == ValueType.String)
            {
                return(returnMatched(string.Compare(left.Text, right.Text, StringComparison.Ordinal) == 0, required,
                                     condition));
            }

            switch (right.Type)
            {
            case ValueType.Any:
                return(returnMatched(true, required, condition));

            case ValueType.TypeName:
                return(returnMatched(right.Compare(left) == 0, required, condition));

            case ValueType.Placeholder:
                Regions.SetBinding(right.Text, left, assigning);
                return(returnMatched(true, required, condition));

            case ValueType.Symbol:
                return(returnMatched(string.Compare(right.Text, left.Text, StringComparison.Ordinal) == 0, required,
                                     condition));
            }

            if (right.IsArray)
            {
                var rightArray = (Array)right.SourceArray;
                if (left is Generator generator)
                {
                    return(returnMatched(generator.Match(rightArray, required, assigning), required, condition));
                }

                if (left.IsArray)
                {
                    var leftArray = (Array)left.SourceArray;
                    return(returnMatched(leftArray.MatchArray(rightArray, required, assigning), required, condition));
                }

                var verb = new Equals();
                return(returnMatched(verb.DoComparison(left, rightArray).IsTrue, required, condition));
            }

            if (right.Type == ValueType.Tuple && left.Type == ValueType.Tuple)
            {
                var leftTuple  = (OTuple)left;
                var rightTuple = (OTuple)right;
                return(returnMatched(leftTuple.Match(rightTuple, required, assigning), required, condition));
            }

            switch (right.Type)
            {
            case ValueType.Block:
                return(returnMatched(((Block)right).IsTrue, required, condition));

            case ValueType.Lambda:
                var closure      = (Lambda)right;
                var variableName = closure.Parameters.VariableName(0, State.DefaultParameterNames.ValueVariable);
                Regions.SetBinding(variableName, left, assigning);
                return(returnMatched(closure.Block.Evaluate().IsTrue, required, condition));

            case ValueType.Message:
                var message = (Message)right;
                return(returnMatched(message.MessageName.EndsWith("?") ? SendMessage(left, message).IsTrue :
                                     MessageManager.MessagingState.RespondsTo(left, message.MessageName), required, condition));

            case ValueType.MessagePath:
                var messageChain = (MessagePath)right;
                return(returnMatched(messageChain.Invoke(left).IsTrue, required, condition));

            case ValueType.Null:
                return(returnMatched(left.Type == ValueType.Null, required, condition));

            case ValueType.Set:
                var set = (Set)right;
                return(returnMatched(set.Contains(left), required, condition));
            }

            if (right is Unto unto)
            {
                return(returnMatched(unto.CompareTo(left), required, condition));
            }

            if (right is Regex regex)
            {
                return(returnMatched(regex.Match(left.Text).IsTrue, required, condition));
            }

            return(returnMatched(right is Pattern pattern ? pattern.MatchAndBind(left.Text) : Runtime.Compare(left, right) == 0, required,
                                 condition));
        }
Example #5
0
 public override int Compare(Value value) => invokeableAsValue.Compare(value);