private void Generate(DekiScriptGenerator expr, DekiScriptGeneratorEvaluationState state) { DekiScriptEnv env = state.Env; // check if __count variable is defined DekiScriptLiteral count; if (!env.Locals.TryGetValue(DekiScriptRuntime.COUNT_ID, out count) || !(count is DekiScriptNumber)) { count = DekiScriptNumber.New(0); env.Locals.Add(DekiScriptRuntime.COUNT_ID, count); } // check if there is a chained generator if (expr.Next != null) { expr.Next.VisitWith(this, state); } else { // call delegate state.Callback(env.NewLocalScope()); // increase __count variable env.Locals.Add(DekiScriptRuntime.COUNT_ID, DekiScriptNumber.New(((DekiScriptNumber)count).Value + 1)); } }
public Empty Visit(DekiScriptGeneratorForeachValue expr, DekiScriptGeneratorEvaluationState state) { DekiScriptLiteral collection = expr.Collection.VisitWith(DekiScriptExpressionEvaluation.Instance, state.Env); // retrieve collection List <DekiScriptLiteral> list; if (collection is DekiScriptList) { // loop over list values list = ((DekiScriptList)collection).Value; } else if (collection is DekiScriptMap) { // loop over map key-value pairs list = new List <DekiScriptLiteral>(((DekiScriptMap)collection).Value.Values); } else if (collection is DekiScriptXml) { // loop over xml selection List <XDoc> selection = ((DekiScriptXml)collection).Value.ToList(); list = new List <DekiScriptLiteral>(selection.Count); foreach (XDoc doc in selection) { list.Add(new DekiScriptXml(doc)); } } else if (collection is DekiScriptNil) { // nothing to do list = new List <DekiScriptLiteral>(); } else { throw new DekiScriptBadTypeException(expr.Line, expr.Column, collection.ScriptType, new DekiScriptType[] { DekiScriptType.LIST, DekiScriptType.MAP, DekiScriptType.XML, DekiScriptType.NIL }); } // loop over collection int index = 0; for (int i = 0; i <= (list.Count - expr.Vars.Length); i += expr.Vars.Length) { // set the environment variable for (int j = 0; j < expr.Vars.Length; ++j) { state.Env.Locals.Add(expr.Vars[j], list[i + j]); } state.Env.Locals.Add(DekiScriptRuntime.INDEX_ID, DekiScriptNumber.New(index)); // iterate over block statements Generate(expr, state); index += expr.Vars.Length; } return(Empty.Value); }
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 Empty Visit(DekiScriptGeneratorForeachKeyValue expr, DekiScriptGeneratorEvaluationState state) { DekiScriptLiteral collection = expr.Collection.VisitWith(DekiScriptExpressionEvaluation.Instance, state.Env); // retrieve collection Dictionary <string, DekiScriptLiteral> map; if (collection is DekiScriptMap) { // loop over map key-value pairs map = ((DekiScriptMap)collection).Value; } else if (collection is DekiScriptNil) { // nothing to do map = new Dictionary <string, DekiScriptLiteral>(); } else { throw new DekiScriptBadTypeException(expr.Line, expr.Column, collection.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.NIL }); } // loop over collection int index = 0; foreach (KeyValuePair <string, DekiScriptLiteral> entry in map) { // set the environment variable state.Env.Locals.Add(expr.Key, DekiScriptString.New(entry.Key)); state.Env.Locals.Add(expr.Value, entry.Value); state.Env.Locals.Add(DekiScriptRuntime.INDEX_ID, DekiScriptNumber.New(index)); // iterate over block statements Generate(expr, state); ++index; } return(Empty.Value); }
internal DekiScriptLiteral Evaluate(DekiScriptAccess expr, DekiScriptEnv env, bool evaluateProperties) { DekiScriptLiteral prefix = expr.Prefix.VisitWith(this, env); DekiScriptLiteral index = expr.Index.VisitWith(this, env); switch (prefix.ScriptType) { case DekiScriptType.MAP: { DekiScriptLiteral result = ((DekiScriptMap)prefix)[index]; if (evaluateProperties) { result = DekiScriptRuntime.EvaluateProperty(result, env); } return(result); } case DekiScriptType.LIST: { DekiScriptLiteral value = DekiScriptNumber.New(index.AsNumber()); DekiScriptLiteral result = ((DekiScriptList)prefix)[value]; if (evaluateProperties) { result = DekiScriptRuntime.EvaluateProperty(result, env); } return(result); } case DekiScriptType.URI: { DekiScriptUri uri = (DekiScriptUri)prefix; // coerce the index type to STR index = DekiScriptString.New(index.AsString()); if (index.ScriptType != DekiScriptType.STR) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, index.ScriptType, new[] { DekiScriptType.STR }); } // curry the argument DekiScriptList args; if (!uri.Arguments.IsNil) { // the uri already has curried parameters, make sure they are in LIST format; otherwise fail if (uri.Arguments.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, uri.Arguments.ScriptType, new[] { DekiScriptType.NIL, DekiScriptType.LIST }); } args = new DekiScriptList((DekiScriptList)uri.Arguments); } else { args = new DekiScriptList(); } args.Add(index); return(new DekiScriptUri(uri.Value, args)); } case DekiScriptType.STR: { DekiScriptString text = (DekiScriptString)prefix; // coerce the index type to NUM double?value = index.AsNumber(); if (value == null) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, index.ScriptType, new[] { DekiScriptType.NUM }); } // retrieve character at given index position int position = (int)value; if ((position < 0) || (position >= text.Value.Length)) { // index is out of bounds, return nil return(DekiScriptNil.Value); } return(DekiScriptString.New(text.Value[position].ToString())); } case DekiScriptType.XML: { string path = index.AsString(); if (path == null) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, index.ScriptType, new[] { DekiScriptType.STR }); } XDoc doc = ((DekiScriptXml)prefix).Value[path]; if (doc.HasName("html")) { doc = DekiScriptLibrary.CleanseHtmlDocument(doc); } return(new DekiScriptXml(doc)); } case DekiScriptType.NIL: return(DekiScriptNil.Value); } throw new DekiScriptBadTypeException(expr.Line, expr.Column, prefix.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST, DekiScriptType.XML, DekiScriptType.STR, DekiScriptType.URI }); }
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); }