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))); } }
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); }
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); }
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)); }
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); }
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)); }
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)); }
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)); }
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")); } }
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); } }
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")); }
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")); } }
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)); }
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); }
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; } }
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)); } }
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; } }
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"); } } }
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); }
public ErlangValue IsPort(ErlangValue value) { return(IsKind(value, ErlangValueKind.Port)); }
public ErlangValue IsBitString(ErlangValue value) { return(IsKind(value, ErlangValueKind.BitString)); }
private static ErlangValue IsKind(ErlangValue value, ErlangValueKind kind) { return(value.Kind == kind ? ErlangAtom.True : ErlangAtom.False); }
public ErlangValue IsFunction(ErlangValue value, ErlangValue airity) { // TODO: implement this return(new ErlangError("is_function/2 nyi")); }
public ErlangValue IsFunction(ErlangValue value) { return(IsKind(value, ErlangValueKind.Fun)); }
public ErlangValue IsTuple(ErlangValue value) { return(IsKind(value, ErlangValueKind.Tuple)); }
public ErlangValue IsAtom(ErlangValue value) { return(IsKind(value, ErlangValueKind.Atom)); }
public ErlangValue IsInteger(ErlangValue value) { return(value.Kind == ErlangValueKind.Number && ((ErlangNumber)value).IsIntegral ? ErlangAtom.True : ErlangAtom.False); }
public ErlangValue IsList(ErlangValue value) { return(IsKind(value, ErlangValueKind.List)); }
public ErlangValue IsNumber(ErlangValue value) { return(IsKind(value, ErlangValueKind.Number)); }
public ErlangValue IsReference(ErlangValue value) { return(IsKind(value, ErlangValueKind.Reference)); }