예제 #1
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            var result = Expression.Evaluate(process);

            if (result.Kind == ErlangValueKind.Error)
            {
                return(result);
            }
            switch (Operator)
            {
            case ErlangOperatorKind.Plus:
                return(ErlangValue.Multiply(result, ErlangNumber.One));

            case ErlangOperatorKind.Minus:
                return(ErlangValue.Multiply(result, ErlangNumber.NegativeOne));

            case ErlangOperatorKind.Not:
                return(ErlangValue.Not(result));

            case ErlangOperatorKind.BNot:
                if (result.Kind == ErlangValueKind.Number)
                {
                    return(ErlangNumber.BNot((ErlangNumber)result));
                }
                else
                {
                    return(new ErlangError("not integral"));
                }

            default:
                return(new ErlangError(string.Format("Invalid unary operator: {0}", Operator)));
            }
        }
예제 #2
0
        private static ErlangValue DoBooleanOp(ErlangValue a, ErlangValue b,
                                               Func <int, int, bool> kindOp,
                                               Func <string, string, bool> atomOp,
                                               Func <ErlangNumber, ErlangNumber, bool> numOp)
        {
            var  ai = (int)a.Kind;
            var  bi = (int)b.Kind;
            bool result;

            if (ai == bi)
            {
                switch (a.Kind)
                {
                case ErlangValueKind.Atom:
                    result = atomOp(((ErlangAtom)a).Name, ((ErlangAtom)b).Name);
                    break;

                case ErlangValueKind.Number:
                    result = numOp((ErlangNumber)a, (ErlangNumber)b);
                    break;

                default:
                    throw new NotImplementedException();
                }
            }
            else
            {
                result = kindOp(ai, bi);
            }

            return(result ? ErlangAtom.True : ErlangAtom.False);
        }
예제 #3
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            ErlangValue result     = null;
            bool        evaluated  = false;
            var         parameters = Parameters.Select(p => p.Evaluate(process)).ToArray();

            if (Module == null)
            {
                var module = GetModule();
                if (module != null)
                {
                    // try to execute from the current module
                    if (module.FunctionExistsInternal(Function, parameters.Length))
                    {
                        result    = module.EvaluateInternal(process, Function, parameters);
                        evaluated = true;
                    }
                }
            }

            if (!evaluated)
            {
                // couldn't execute from this module, kick it back to the ErlangProcess to find the function
                result = process.Evaluate(Module, Function, parameters);
            }

            return(result);
        }
예제 #4
0
 public static ErlangValue PlusPlus(ErlangValue list, ErlangValue tail)
 {
     if (list.Kind != ErlangValueKind.List)
     {
         return(new ErlangError("not a list"));
     }
     return(ErlangList.CloneWithTail((ErlangList)list, tail));
 }
예제 #5
0
 private static ErlangValue OperationWithBooleans(ErlangValue a, ErlangValue b, Func <bool, bool, bool> operation)
 {
     if (!(ErlangAtom.IsTrue(a) || ErlangAtom.IsFalse(a)) || !(ErlangAtom.IsTrue(b) || ErlangAtom.IsFalse(b)))
     {
         return(new ErlangError("not numbers"));
     }
     return(operation(ErlangAtom.IsTrue(a), ErlangAtom.IsTrue(b)) ? ErlangAtom.True : ErlangAtom.False);
 }
예제 #6
0
 private static ErlangValue OperationWithNumbers(ErlangValue a, ErlangValue b, Func <ErlangNumber, ErlangNumber, ErlangValue> operation)
 {
     if (a == null || a.Kind != ErlangValueKind.Number || b == null || b.Kind != ErlangValueKind.Number)
     {
         return(new ErlangError("not numbers"));
     }
     return(operation((ErlangNumber)a, (ErlangNumber)b));
 }
예제 #7
0
 public static ErlangValue EqualsColonEquals(ErlangValue a, ErlangValue b)
 {
     // this only matters for numbers
     if (a.Kind == ErlangValueKind.Number && b.Kind == ErlangValueKind.Number)
     {
         return(ErlangNumber.ExactlyEquals((ErlangNumber)a, (ErlangNumber)b) ? ErlangAtom.True : ErlangAtom.False);
     }
     return(EqualsEquals(a, b));
 }
예제 #8
0
        public ErlangValue Evaluate(ErlangProcess process, string functionName, ErlangValue[] parameters)
        {
            ErlangValue error = null;

            if (functionName == "module_info")
            {
                if (parameters.Length == 0)
                {
                    return(ModuleInfo);
                }
                else if (parameters.Length == 1)
                {
                    if (parameters[0].Kind == ErlangValueKind.Atom)
                    {
                        var text = ((ErlangAtom)parameters[0]).Name;
                        if (text == "functions")
                        {
                            return(AllFunctions);
                        }
                        else
                        {
                            // find matching tuple
                            var list = ModuleInfo;
                            while (list != null && list.Value != null)
                            {
                                Debug.Assert(list.Value is ErlangTuple);
                                var tuple = (ErlangTuple)list.Value;
                                Debug.Assert(tuple.Airity == 2);
                                Debug.Assert(tuple.Values[0].Kind == ErlangValueKind.Atom);
                                if (((ErlangAtom)tuple.Values[0]).Name == text)
                                {
                                    Debug.Assert(tuple.Values[1].Kind == ErlangValueKind.List);
                                    return(tuple.Values[1]);
                                }

                                list = list.Tail as ErlangList;
                            }

                            return(new ErlangError("no matching tuple item"));
                        }
                    }
                    else
                    {
                        error = new ErlangError("no matching function");
                    }
                }
                else
                {
                    error = new ErlangError("no matching function");
                }
            }
            error = error ?? parameters.FirstOrDefault(p => p.Kind == ErlangValueKind.Error);
            return(error ?? EvaluateLocal(process, functionName, parameters));
        }
예제 #9
0
 public ErlangValue GetModuleInfo(ErlangValue module)
 {
     if (module.Kind == ErlangValueKind.Atom)
     {
         return(Process.Evaluate(((ErlangAtom)module).Name, "module_info"));
     }
     else
     {
         return(new ErlangError("must be called with atom"));
     }
 }
예제 #10
0
 public static bool IsEmptyList(ErlangValue item)
 {
     if (item != null && item.Kind == ErlangValueKind.List)
     {
         var list = (ErlangList)item;
         return(list.Value == null && list.Tail == null);
     }
     else
     {
         return(false);
     }
 }
예제 #11
0
        public ErlangValue Length(ErlangValue list)
        {
            if (list.Kind == ErlangValueKind.List)
            {
                var length = ((ErlangList)list).Length;
                if (length < 0)
                {
                    return(new ErlangError("not a proper list"));
                }
                return(new ErlangNumber(length));
            }

            return(new ErlangError("not a list"));
        }
예제 #12
0
 public static ErlangValue Not(ErlangValue value)
 {
     if (ErlangAtom.IsTrue(value))
     {
         return(ErlangAtom.False);
     }
     else if (ErlangAtom.IsFalse(value))
     {
         return(ErlangAtom.True);
     }
     else
     {
         return(new ErlangError("not a boolean"));
     }
 }
예제 #13
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            var values = new ErlangValue[Elements.Length];

            for (int i = 0; i < Elements.Length; i++)
            {
                var value = Elements[i].Evaluate(process);
                if (value.Kind == ErlangValueKind.Error)
                {
                    return(value);
                }
                values[i] = value;
            }

            return(new ErlangTuple(values));
        }
예제 #14
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            var values = new ErlangValue[Elements.Length];

            for (int i = 0; i < Elements.Length; i++)
            {
                var value = Elements[i].Evaluate(process);
                if (value.Kind == ErlangValueKind.Error)
                {
                    return(value);
                }
                values[i] = value;
            }

            var list = new ErlangList(values, Tail == null ? null : Tail.Evaluate(process));

            return(list);
        }
예제 #15
0
 private ErlangList(ErlangValue[] values, int index, ErlangValue tail)
 {
     if (values != null && index < values.Length)
     {
         Value = values[index];
         if (index == values.Length - 1)
         {
             Tail = tail ?? new ErlangList();
         }
         else
         {
             Tail = new ErlangList(values, index + 1, tail);
         }
         var tailLength = Tail.Kind == ErlangValueKind.List
             ? ((ErlangList)Tail).Length
             : -1;
         Length = tailLength < 0 ? -1 : tailLength + 1;
     }
 }
예제 #16
0
 internal static ErlangValue CloneWithTail(ErlangList list, ErlangValue tail)
 {
     if (IsEmptyList(list.Tail))
     {
         return(new ErlangList(list.Value, tail));
     }
     else if (list.Tail != null && list.Tail.Kind != ErlangValueKind.List)
     {
         return(new ErlangError("can't concat"));
     }
     else
     {
         var newTail = CloneWithTail((ErlangList)list.Tail, tail);
         if (newTail.Kind == ErlangValueKind.Error)
         {
             return(newTail);
         }
         return(new ErlangList(list.Value, newTail));
     }
 }
예제 #17
0
 public ErlangList(ErlangValue value, ErlangValue tail)
 {
     if (value == null && tail != null)
     {
         throw new ArgumentException("Tail cannot be present without a value.");
     }
     Value = value;
     Tail  = tail;
     if (Value == null && Tail == null)
     {
         Length = 0;
     }
     else if (Tail == null || Tail.Kind != ErlangValueKind.List)
     {
         Length = -1;
     }
     else
     {
         var tailLength = ((ErlangList)Tail).Length + 1;
         Length = tailLength < 0 ? -1 : tailLength + 1;
     }
 }
예제 #18
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            // variable assignment or pattern match
            if (Operator == ErlangOperatorKind.Equals)
            {
                // first evaluate the right side
                var right = Right.Evaluate(process);
                if (right.Kind == ErlangValueKind.Error)
                {
                    return(right);
                }

                // now match to the left
                if (ErlangBinder.TryBindParameter(Left, right, process.CallStack.CurrentFrame))
                {
                    return(right);
                }
                else
                {
                    return(new ErlangError("bad match"));
                }
            }

            var left = Left.Evaluate(process);

            if (left.Kind == ErlangValueKind.Error)
            {
                return(left);
            }
            if (IsShortCircuitOperator(Operator))
            {
                switch (Operator)
                {
                case ErlangOperatorKind.AndAlso:
                    if (ErlangAtom.IsTrue(left))
                    {
                        return(Right.Evaluate(process));
                    }
                    else
                    {
                        return(ErlangAtom.False);
                    }

                case ErlangOperatorKind.OrElse:
                    if (ErlangAtom.IsTrue(left))
                    {
                        return(left);
                    }
                    else
                    {
                        return(Right.Evaluate(process));
                    }

                default:
                    throw new ArgumentException("invalid operator");
                }
            }
            else
            {
                var right = Right.Evaluate(process);
                if (right.Kind == ErlangValueKind.Error)
                {
                    return(right);
                }
                switch (Operator)
                {
                case ErlangOperatorKind.Plus:
                    return(ErlangValue.Add(left, right));

                case ErlangOperatorKind.Minus:
                    return(ErlangValue.Subtract(left, right));

                case ErlangOperatorKind.Asterisk:
                    return(ErlangValue.Multiply(left, right));

                case ErlangOperatorKind.Slash:
                    return(ErlangValue.Divide(left, right));

                case ErlangOperatorKind.And:
                    return(ErlangValue.And(left, right));

                case ErlangOperatorKind.Or:
                    return(ErlangValue.Or(left, right));

                case ErlangOperatorKind.Less:
                    return(ErlangValue.Less(left, right));

                case ErlangOperatorKind.EqualsLess:
                    return(ErlangValue.LessEquals(left, right));

                case ErlangOperatorKind.Greater:
                    return(ErlangValue.Greater(left, right));

                case ErlangOperatorKind.GreaterEquals:
                    return(ErlangValue.GreaterEquals(left, right));

                case ErlangOperatorKind.EqualsEquals:
                    return(ErlangValue.EqualsEquals(left, right));

                case ErlangOperatorKind.SlashEquals:
                    return(ErlangValue.SlashEquals(left, right));

                case ErlangOperatorKind.EqualsColonEquals:
                    return(ErlangValue.EqualsColonEquals(left, right));

                case ErlangOperatorKind.EqualsSlashEquals:
                    return(ErlangValue.EqualsSlashEquals(left, right));

                case ErlangOperatorKind.PlusPlus:
                    return(ErlangValue.PlusPlus(left, right));

                default:
                    throw new ArgumentException("invalid operator");
                }
            }
        }
예제 #19
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            ErlangValue last = null;
            ErlangExpressionBlockExpression def    = this;
            ErlangCompiledModule            module = GetModule();
            var  children   = def.GetChildren();
            bool doTailCall = false;

            do
            {
                doTailCall = false; // ensure we're reset from the last loop
                // evaluate each expression
                Debug.Assert(children.Length > 0);
                for (int i = 0; !doTailCall && i < children.Length; i++)
                {
                    var    expression = children[i];
                    string moduleName = null;
                    ErlangFunctionInvocationExpression function = null;
                    ErlangStackFrame tailCallCandidate          = null;
                    if (UseTailCalls && i == children.Length - 1 && expression is ErlangFunctionInvocationExpression && expression.IsLastChild)
                    {
                        // if last expression and it's a function invocation
                        function          = (ErlangFunctionInvocationExpression)expression;
                        moduleName        = function.Module ?? module.Name;
                        tailCallCandidate = process.CallStack.GetTailCallCandidate(
                            moduleName,
                            function.Function,
                            function.Parameters.Length);
                        doTailCall = tailCallCandidate != null;
                    }

                    if (doTailCall)
                    {
                        // evaluate parameters
                        var evaledParams = new ErlangValue[function.Parameters.Length];
                        for (int j = 0; j < function.Parameters.Length; j++)
                        {
                            var value = function.Parameters[j].Evaluate(process);
                            if (value.Kind == ErlangValueKind.Error)
                            {
                                return(value);
                            }
                            evaledParams[j] = value;
                        }

                        // prepare new frame
                        var newFrame = new ErlangStackFrame(tailCallCandidate.Module,
                                                            tailCallCandidate.Function,
                                                            tailCallCandidate.Airity);
                        process.CallStack.RewindForTailCall(newFrame);

                        // find the new definition
                        var group = module.GetFunction(function.Function, evaledParams.Length);
                        def = group.GetFunctionOverload(process, evaledParams);
                        if (def == null)
                        {
                            return(new ErlangAtom("no_such_tailcall_function"));
                        }
                        children = def.GetChildren();
                    }
                    else
                    {
                        // not a tailcall, just invoke normally
                        last = children[i].Evaluate(process);
                        if (last.Kind == ErlangValueKind.Error)
                        {
                            return(last); // decrease scope?
                        }
                    }
                }
            } while (doTailCall);

            return(last);
        }
예제 #20
0
 public ErlangValue IsPort(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Port));
 }
예제 #21
0
 public ErlangValue IsBitString(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.BitString));
 }
예제 #22
0
 private static ErlangValue IsKind(ErlangValue value, ErlangValueKind kind)
 {
     return(value.Kind == kind ? ErlangAtom.True : ErlangAtom.False);
 }
예제 #23
0
 public ErlangValue IsFunction(ErlangValue value, ErlangValue airity)
 {
     // TODO: implement this
     return(new ErlangError("is_function/2 nyi"));
 }
예제 #24
0
 public ErlangValue IsFunction(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Fun));
 }
예제 #25
0
 public ErlangValue IsTuple(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Tuple));
 }
예제 #26
0
 public ErlangValue IsAtom(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Atom));
 }
예제 #27
0
 public ErlangValue IsInteger(ErlangValue value)
 {
     return(value.Kind == ErlangValueKind.Number && ((ErlangNumber)value).IsIntegral
         ? ErlangAtom.True
         : ErlangAtom.False);
 }
예제 #28
0
 public ErlangValue IsList(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.List));
 }
예제 #29
0
 public ErlangValue IsNumber(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Number));
 }
예제 #30
0
 public ErlangValue IsReference(ErlangValue value)
 {
     return(IsKind(value, ErlangValueKind.Reference));
 }