public DekiScriptLiteral Visit(DekiScriptVar expr, DekiScriptEnv env) { if (expr.Name.EqualsInvariant(DekiScriptRuntime.ENV_ID)) { DekiScriptMap vars = new DekiScriptMap(); vars.AddRange(env.Globals); vars.AddRange(env.Locals); return(vars); } // check if variable exists DekiScriptLiteral result = env[expr.Name]; if (result == null) { throw new DekiScriptUndefinedNameException(expr.Line, expr.Column, expr.Name); } result = DekiScriptRuntime.EvaluateProperty(result, env); return(result); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptVar expr, DekiScriptExpressionEvaluationState state) { if (expr.Name.EqualsInvariant(DekiScriptRuntime.ENV_ID)) { DekiScriptMap vars = new DekiScriptMap(); vars.AddRange(state.Env.Vars); return(state.Push(vars)); } // check if variable exists DekiScriptLiteral result; if (!state.Env.Vars.TryGetValue(expr.Name, out result)) { result = state.Runtime.ResolveMissingName(expr.Name); } if (result == null) { throw new DekiScriptUndefinedNameException(expr.Location, expr.Name); } result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env); return(state.Push(result)); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptBinary expr, DekiScriptExpressionEvaluationState state) { DekiScriptExpression Left = expr.Left; DekiScriptExpression Right = expr.Right; switch (expr.OpCode) { case DekiScriptBinary.Op.LeftValue: return(Left.VisitWith(this, state)); case DekiScriptBinary.Op.IdentityEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.IdentityEqual(left, right))); } case DekiScriptBinary.Op.IdentityNotEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.IdentityNotEqual(left, right))); } case DekiScriptBinary.Op.IsType: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); string type = ((DekiScriptString)Right).Value; return(state.Push(DekiScriptExpression.Constant(type.EqualsInvariantIgnoreCase("any") || left.ScriptTypeName.EqualsInvariantIgnoreCase(type)))); } case DekiScriptBinary.Op.Equal: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.Equal(left, right))); } case DekiScriptBinary.Op.NotEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.NotEqual(left, right))); } case DekiScriptBinary.Op.GreaterOrEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() >= right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) >= 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.GreaterThan: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() > right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) > 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LessOrEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() <= right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) <= 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LessThan: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() < right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) < 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LogicalAnd: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (!result.IsNilFalseZero) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.LogicalOr: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (result.IsNilFalseZero) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.Addition: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() + state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Division: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() / state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Modulo: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); 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(state.Push(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue)))); } else { return(state.Push(DekiScriptExpression.Constant(left.AsNumber() % right.AsNumber()))); } } case DekiScriptBinary.Op.Multiplication: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() * state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Subtraction: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() - state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.NullCoalesce: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (result.IsNil) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.Concat: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (left is DekiScriptNil) { return(state.Push(right)); } else if (right is DekiScriptNil) { return(state.Push(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(state.Push(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(state.Push(result)); } else { // treat left and right expressions as strings string leftText = left.AsString(); string rightText = right.AsString(); if ((leftText != null) && (rightText != null)) { return(state.Push(DekiScriptExpression.Constant(leftText + rightText))); } else if (leftText != null) { return(state.Push(DekiScriptExpression.Constant(leftText))); } else if (rightText != null) { return(state.Push(DekiScriptExpression.Constant(rightText))); } else { return(DekiScriptOutputBuffer.Range.Empty); } } } 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(state.Pop(Left.VisitWith(this, state)).AsString()); string result = null; if (left != null) { DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); 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(state.Push(DekiScriptLiteral.FromNativeValue(result))); } case DekiScriptBinary.Op.InCollection: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (right is DekiScriptList) { foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(state.Push(DekiScriptBool.True)); } } return(state.Push(DekiScriptBool.False)); } else if (right is DekiScriptMap) { foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(state.Push(DekiScriptBool.True)); } } return(state.Push(DekiScriptBool.False)); } else { return(state.Push(DekiScriptBool.False)); } } } throw new InvalidOperationException("invalid op code:" + expr.OpCode); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptCall expr, DekiScriptExpressionEvaluationState state) { state.ThrowIfTimedout(); // evaluate prefix DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state)); if (prefix.ScriptType != DekiScriptType.URI) { if (prefix.ScriptType == DekiScriptType.NIL) { throw new DekiScriptUndefinedNameException(expr.Location, expr.Prefix.ToString()); } else { throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.URI }); } } // evaluate arguments DekiScriptLiteral arguments = state.Pop(expr.Arguments.VisitWith(this, state)); if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST)) { throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST }); } // check if the URI was curried DekiScriptUri uri = (DekiScriptUri)prefix; if (!uri.Arguments.IsNil) { switch (uri.Arguments.ScriptType) { case DekiScriptType.LIST: // append argument to list DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments); list.Add(arguments); arguments = list; break; case DekiScriptType.MAP: if (arguments.ScriptType == DekiScriptType.MAP) { // concatenate both maps DekiScriptMap map = new DekiScriptMap(); map.AddRange((DekiScriptMap)uri.Arguments); map.AddRange((DekiScriptMap)arguments); arguments = map; } else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0) { // we can't append a list to a map throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP }); } break; default: throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST }); } } // check if this is an invocation or curry operation if (expr.IsCurryOperation) { return(state.Push(new DekiScriptUri(uri.Value, arguments))); } // invoke function try { return(state.Push(state.Runtime.Invoke(expr.Location, uri.Value, arguments, state.Env))); } catch (DekiScriptFatalException) { throw; } catch (Exception e) { var descriptor = state.Runtime.ResolveRegisteredFunctionUri(uri.Value); throw new DekiScriptInvokeException(expr.Location, uri.Value, (descriptor != null) ? descriptor.Name : uri.Value.ToString(), e); } }
public DekiScriptLiteral Visit(DekiScriptCall expr, DekiScriptEnv env) { // evaluate prefix DekiScriptLiteral prefix = expr.Prefix.VisitWith(this, env); if (prefix.ScriptType != DekiScriptType.URI) { if (prefix.ScriptType == DekiScriptType.NIL) { throw new DekiScriptUndefinedNameException(expr.Line, expr.Column, expr.Prefix.ToString()); } else { throw new DekiScriptBadTypeException(expr.Line, expr.Column, prefix.ScriptType, new DekiScriptType[] { DekiScriptType.URI }); } } // evaluate arguments DekiScriptLiteral arguments = expr.Arguments.VisitWith(this, env); if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST)) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST }); } // check if the URI was curried DekiScriptUri uri = (DekiScriptUri)prefix; if (!uri.Arguments.IsNil) { switch (uri.Arguments.ScriptType) { case DekiScriptType.LIST: // append argument to list DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments); list.Add(arguments); arguments = list; break; case DekiScriptType.MAP: if (arguments.ScriptType == DekiScriptType.MAP) { // concatenate both maps DekiScriptMap map = new DekiScriptMap(); map.AddRange((DekiScriptMap)uri.Arguments); map.AddRange((DekiScriptMap)arguments); arguments = map; } else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0) { // we can't append a list to a map throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP }); } break; default: throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST }); } } // check if this is an invocation or curry operation if (expr.IsCurryOperation) { return(new DekiScriptUri(uri.Value, arguments)); } else { // invoke function return(Coroutine.Invoke(DekiScriptRuntime.Invoke, uri.Value, arguments, env, new Result <DekiScriptLiteral>()).Wait()); } }