示例#1
0
文件: Utility.cs 项目: loki3/loki-pl1
        /// <summary>
        /// If bCreate, always set value on current scope,
        /// else, change value on scope value exists on or throw exception if it doesn't exist
        /// </summary>
        /// <returns>true if it actually set a value</returns>
        internal static bool SetOnScope(IScope scope, string key, Value value, bool bCreate, bool bOverload, bool bInitOnly)
        {
            // figure out the scope to modify
            IScope where;
            if (bCreate)
            {
                where = scope;
            }
            else
            {
                where = scope.Exists(key);
                if (where == null)
                    throw new Loki3Exception().AddBadToken(new Token(key));
            }

            // if we're setting a function, it may be an overload
            if (bOverload && value.Type == ValueType.Function)
            {
                // first, if there's nothing there, see if key exists on an ancestor scope
                bool bFound = where.AsMap.ContainsKey(key);
                if (!bFound)
                {
                    IScope ancestor = scope.Exists(key);
                    if (ancestor != null)
                    {
                        Value existing = ancestor.AsMap[key];
                        if (existing.Type == ValueType.Function)
                        {	// copy function(s) to this scope so we can overload it
                            // and yet this definition only exists in this scope
                            Value copiedToThisScope = existing.Copy();
                            where.SetValue(key, copiedToThisScope);
                            bFound = true;
                        }
                    }
                }

                if (bFound)
                {
                    Value existing = where.AsMap[key];
                    ValueFunctionOverload overload = null;
                    if (existing.Type == ValueType.Function)
                    {	// change function value into an overload value
                        overload = existing as ValueFunctionOverload;
                        if (overload == null)
                        {
                            overload = new ValueFunctionOverload(existing as ValueFunction);
                            overload.Add(value as ValueFunction);
                            where.SetValue(key, overload);
                        }
                        else
                        {
                            overload.Add(value as ValueFunction);
                        }
                        return true;
                    }
                }
            }

            if (bInitOnly && where.AsMap.ContainsKey(key))
                return false;
            where.SetValue(key, value);
            return true;
        }
        public void TestBasic()
        {
            ValueFunctionOverload overload = new ValueFunctionOverload();
            IScope scope = new ScopeChain();

            {	// add a single function & make sure it's called at right time & fails at right time
                ValueFunction numInt = new Add(ValueType.Number, ValueType.Int, 0);
                overload.Add(numInt);
                Value a = overload.Eval(null, MakePair(3, 4, true, true), scope, scope, null, null);
                Assert.AreEqual(7, a.AsInt);
                Value b = overload.Eval(null, MakePair(3, 5, false, true), scope, scope, null, null);
                Assert.AreEqual(8, b.AsFloat);

                bool bThrew = false;
                try
                {
                    overload.Eval(null, MakePair(3, 4, false, false), scope, scope, null, null);
                }
                catch (Loki3Exception)
                {
                    bThrew = true;
                }
                Assert.IsTrue(bThrew);
            }

            {	// add a second function & make sure both succeed & fail at right time
                // this one is more specific so should get called first when signature matches
                ValueFunction intInt = new Add(ValueType.Int, ValueType.Int, 1);
                overload.Add(intInt);
                Value a = overload.Eval(null, MakePair(3, 4, true, true), scope, scope, null, null);
                Assert.AreEqual(8, a.AsInt);	// calls 2nd version
                Value b = overload.Eval(null, MakePair(3, 5, false, true), scope, scope, null, null);
                Assert.AreEqual(8, b.AsFloat);	// calls 1st version

                bool bThrew = false;
                try
                {	// still no match for this one
                    overload.Eval(null, MakePair(3, 4, false, false), scope, scope, null, null);
                }
                catch (Loki3Exception)
                {
                    bThrew = true;
                }
                Assert.IsTrue(bThrew);
            }

            {	// try adding a postfix function to the overload
                bool bThrew = false;
                try
                {
                    ValueFunction post = new Post();
                    overload.Add(post);
                }
                catch (Loki3Exception e)
                {
                    Assert.AreEqual("prefix", e.Errors[Loki3Exception.keyExpectedFix].ToString());
                    Assert.AreEqual("postfix", e.Errors[Loki3Exception.keyActualFix].ToString());
                    bThrew = true;
                }
                Assert.IsTrue(bThrew);
            }
        }