public DekiScriptLiteral Visit(DekiScriptUnary expr, DekiScriptEnv env) { switch (expr.OpCode) { case DekiScriptUnary.Op.Negate: return(DekiScriptNumber.New(-expr.Value.VisitWith(this, env).AsNumber())); case DekiScriptUnary.Op.LogicalNot: return(DekiScriptBool.New(expr.Value.VisitWith(this, env).IsNilFalseZero)); case DekiScriptUnary.Op.TypeOf: return(DekiScriptString.New(expr.Value.VisitWith(this, env).ScriptTypeName)); case DekiScriptUnary.Op.Length: { DekiScriptLiteral value = expr.Value.VisitWith(this, env); switch (value.ScriptType) { case DekiScriptType.NIL: return(DekiScriptNumber.New(0)); case DekiScriptType.LIST: return(DekiScriptNumber.New(((DekiScriptList)value).Value.Count)); case DekiScriptType.STR: return(DekiScriptNumber.New(((DekiScriptString)value).Value.Length)); case DekiScriptType.MAP: return(DekiScriptNumber.New(((DekiScriptMap)value).Value.Count)); case DekiScriptType.XML: return(DekiScriptNumber.New(((DekiScriptXml)value).Value.ListLength)); default: return(DekiScriptNil.Value); } } } throw new InvalidOperationException("invalid op code:" + expr.OpCode); }
public DekiScriptLiteral Visit(DekiScriptBinary expr, DekiScriptEnv env) { DekiScriptExpression Left = expr.Left; DekiScriptExpression Right = expr.Right; switch (expr.OpCode) { case DekiScriptBinary.Op.LeftValue: return(Left.VisitWith(this, env)); case DekiScriptBinary.Op.IdentityEqual: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); return(DekiScriptBinary.IdentityEqual(left, right)); } case DekiScriptBinary.Op.IdentityNotEqual: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); return(DekiScriptBinary.IdentityNotEqual(left, right)); } case DekiScriptBinary.Op.IsType: { DekiScriptLiteral left = Left.VisitWith(this, env); string type = ((DekiScriptString)Right).Value; return(DekiScriptBool.New(StringUtil.EqualsInvariantIgnoreCase(type, "any") || StringUtil.EqualsInvariantIgnoreCase(left.ScriptTypeName, type))); } case DekiScriptBinary.Op.Equal: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); return(DekiScriptBinary.Equal(left, right)); } case DekiScriptBinary.Op.NotEqual: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); return(DekiScriptBinary.NotEqual(left, right)); } case DekiScriptBinary.Op.GreaterOrEqual: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(DekiScriptBool.New(left.AsNumber() >= right.AsNumber())); case DekiScriptType.STR: return(DekiScriptBool.New(StringUtil.CompareInvariant(left.AsString(), right.AsString()) >= 0)); default: return(DekiScriptNil.Value); } } else { return(DekiScriptNil.Value); } } case DekiScriptBinary.Op.GreaterThan: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(DekiScriptBool.New(left.AsNumber() > right.AsNumber())); case DekiScriptType.STR: return(DekiScriptBool.New(StringUtil.CompareInvariant(left.AsString(), right.AsString()) > 0)); default: return(DekiScriptNil.Value); } } else { return(DekiScriptNil.Value); } } case DekiScriptBinary.Op.LessOrEqual: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(DekiScriptBool.New(left.AsNumber() <= right.AsNumber())); case DekiScriptType.STR: return(DekiScriptBool.New(StringUtil.CompareInvariant(left.AsString(), right.AsString()) <= 0)); default: return(DekiScriptNil.Value); } } else { return(DekiScriptNil.Value); } } case DekiScriptBinary.Op.LessThan: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(DekiScriptBool.New(left.AsNumber() < right.AsNumber())); case DekiScriptType.STR: return(DekiScriptBool.New(StringUtil.CompareInvariant(left.AsString(), right.AsString()) < 0)); default: return(DekiScriptNil.Value); } } else { return(DekiScriptNil.Value); } } case DekiScriptBinary.Op.LogicalAnd: { DekiScriptLiteral result = Left.VisitWith(this, env); if (!result.IsNilFalseZero) { result = Right.VisitWith(this, env); } return(result); } case DekiScriptBinary.Op.LogicalOr: { DekiScriptLiteral result = Left.VisitWith(this, env); if (result.IsNilFalseZero) { result = Right.VisitWith(this, env); } return(result); } case DekiScriptBinary.Op.Addition: return(DekiScriptNumber.New(Left.VisitWith(this, env).AsNumber() + Right.VisitWith(this, env).AsNumber())); case DekiScriptBinary.Op.Division: return(DekiScriptNumber.New(Left.VisitWith(this, env).AsNumber() / Right.VisitWith(this, env).AsNumber())); case DekiScriptBinary.Op.Modulo: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if ((left is DekiScriptString) && ((right is DekiScriptMap) || (right is DekiScriptList))) { // NOTE (steveb): string.format shorthand notation: "abc = $abc" % { abc: 123 } -OR- "0 = $0" % [ 123 ] return(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue))); } else { return(DekiScriptNumber.New(left.AsNumber() % right.AsNumber())); } } case DekiScriptBinary.Op.Multiplication: return(DekiScriptNumber.New(Left.VisitWith(this, env).AsNumber() * Right.VisitWith(this, env).AsNumber())); case DekiScriptBinary.Op.Subtraction: return(DekiScriptNumber.New(Left.VisitWith(this, env).AsNumber() - Right.VisitWith(this, env).AsNumber())); case DekiScriptBinary.Op.NullCoalesce: { DekiScriptLiteral result = Left.VisitWith(this, env); if (result.IsNil) { result = Right.VisitWith(this, env); } return(result); } case DekiScriptBinary.Op.Concat: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (left is DekiScriptNil) { return(right); } else if (right is DekiScriptNil) { return(left); } else if ((left is DekiScriptMap) && (right is DekiScriptMap)) { // left and right expressions are maps, merge them DekiScriptMap result = new DekiScriptMap(); result.AddRange((DekiScriptMap)left); result.AddRange((DekiScriptMap)right); return(result); } else if ((left is DekiScriptList) && (right is DekiScriptList)) { // left and right expressions are lists, concatenate them DekiScriptList result = new DekiScriptList(); result.AddRange((DekiScriptList)left); result.AddRange((DekiScriptList)right); return(result); } else { // treat left and right expressions as strings string leftText = left.AsString(); string rightText = right.AsString(); if ((leftText != null) && (rightText != null)) { return(DekiScriptString.New(leftText + rightText)); } else if (leftText != null) { return(DekiScriptString.New(leftText)); } else if (rightText != null) { return(DekiScriptString.New(rightText)); } else { return(DekiScriptNil.Value); } } } case DekiScriptBinary.Op.UriAppend: { // TODO (steveb): we should throw an exception when the LHS is not a valid string or uri XUri left = XUri.TryParse(Left.VisitWith(this, env).AsString()); string result = null; if (left != null) { DekiScriptLiteral right = Right.VisitWith(this, env); if (right is DekiScriptString) { result = DekiScriptLibrary.UriBuild(left, right.AsString(), null); } else if (right is DekiScriptMap) { result = DekiScriptLibrary.UriBuild(left, null, (Hashtable)right.NativeValue); } else { result = left.ToString(); } } return(DekiScriptLiteral.FromNativeValue(result)); } case DekiScriptBinary.Op.InCollection: { DekiScriptLiteral left = Left.VisitWith(this, env); DekiScriptLiteral right = Right.VisitWith(this, env); if (right is DekiScriptList) { foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(DekiScriptBool.True); } } return(DekiScriptBool.False); } else if (right is DekiScriptMap) { foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(DekiScriptBool.True); } } return(DekiScriptBool.False); } else { return(DekiScriptBool.False); } } } throw new InvalidOperationException("invalid op code:" + expr.OpCode); }