NewArrayInit() public static method

Creates a NewArrayExpression of the specified type from the provided initializers.
public static NewArrayInit ( Type type ) : NewArrayExpression
type Type A Type that represents the element type of the array.
return NewArrayExpression
Ejemplo n.º 1
0
        public void NewArrayInit()
        {
            var expected = LinqExpression.NewArrayInit(typeof(long), LinqExpression.Constant(0L));

            using var g = new GraphEngine.Graph();
            g.LoadFromString(@"
@prefix : <http://example.com/> .

:s
    a :NewArrayInit ;
    :newArrayType [
        :typeName ""System.Int64"" ;
    ] ;
    :newArrayExpressions (
        [
            :constantValue 0 ;
        ]
    ) ;
.
");
            var s = g.GetUriNode(":s");

            var actual = Expression.Parse(s).LinqExpression;

            Console.WriteLine(actual.GetDebugView());

            actual.Should().Be(expected);
        }
        public void NewArrayInit()
        {
            var expression =
                LinqExpression.NewArrayInit(
                    typeof(long),
                    LinqExpression.Constant(0L));

            ShouldRoundrip(expression);
        }
Ejemplo n.º 3
0
        public static Expression CreateSet(HashSet <Expression> values)
        {
            var valueType = values.First().Type;
            var setType   = typeof(HashSet <>).MakeGenericType(valueType);
            var ctor      = setType.GetConstructor(new [] { typeof(IEnumerable <>).MakeGenericType(valueType) });
            var args      = LinqExpression.NewArrayInit(valueType, values.Select(x => x.internalExpression));

            return(new Expression(LinqExpression.New(ctor, args)));
        }
Ejemplo n.º 4
0
        public static Expression CreateDictionary(IList <Expression> keys, IList <Expression> values)
        {
            var keyType   = keys.First().Type;
            var valueType = values.First().Type;
            var method    = typeof(Expression).GetMethod("CreateDictionaryHelper", BindingFlags.Static | BindingFlags.NonPublic);

            method = method.MakeGenericMethod(keyType, valueType);
            var keysArg   = LinqExpression.NewArrayInit(keyType, keys.Select(x => x.internalExpression));
            var valuesArg = LinqExpression.NewArrayInit(valueType, values.Select(x => x.internalExpression));

            return(new Expression(LinqExpression.Call(method, keysArg, valuesArg)));
        }
Ejemplo n.º 5
0
        void ConvertArgumentToParamType(List <Argument> arguments, ParameterInfo[] parameters, out Expr failExpr)
        {
            failExpr = null;

            for (int i = 0; i < arguments.Count; i++)
            {
                var arg   = arguments[i];
                var param = parameters[i];

                if (param.ParameterType == typeof(bool) && arg.Type != typeof(bool))
                {
                    arg.Expression = ExprHelpers.ConvertToBoolean(context, arg.Expression);
                }
                else if (param.ParameterType == typeof(double) && arg.Type == typeof(string))
                {
                    arg.Expression = ExprHelpers.ConvertToNumberAndCheck(
                        context, arg.Expression,
                        ExceptionMessage.INVOKE_BAD_ARGUMENT_GOT, i + 1, "number", "string");
                }
                else if (param.ParameterType == typeof(string) && arg.Type != typeof(string))
                {
                    arg.Expression = Expr.Call(arg.Expression, MemberInfos.ObjectToString, arg.Expression);
                }
                else
                {
                    if (arg.Type == param.ParameterType || arg.Type.IsSubclassOf(param.ParameterType))
                    {
                        arg.Expression = Expr.Convert(arg.Expression, param.ParameterType);
                    }
                    else
                    {
                        Func <Expr, Expr> typeNameExpr =
                            obj => Expr.Invoke(
                                Expr.Constant((Func <object, string>)BaseLibrary.Type),
                                Expr.Convert(obj, typeof(object)));

                        // Ugly reflection hack
                        failExpr = Expr.Throw(
                            Expr.New(
                                MemberInfos.NewRuntimeException,
                                Expr.Constant(ExceptionMessage.INVOKE_BAD_ARGUMENT_GOT),
                                Expr.NewArrayInit(
                                    typeof(object),
                                    Expr.Constant(i + 1, typeof(object)),
                                    typeNameExpr(Expr.Constant(Activator.CreateInstance(param.ParameterType))),
                                    typeNameExpr(arg.Expression))));
                        break;
                    }
                }
            }
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Gets an expression representing the value of one or more expressions, as used by a return statement
 /// </summary>
 Expr GetMultiExpressionValue(ParseTreeNode expressionList)
 {
     if (expressionList.ChildNodes.Count == 0)
     {
         return(Expr.Constant(null, typeof(object)));
     }
     if (expressionList.ChildNodes.Count == 1)
     {
         return(CompileExpression(expressionList.ChildNodes[0]));
     }
     else
     {
         return(Expr.NewArrayInit(typeof(object), expressionList.ChildNodes.Select(CompileExpression)));
     }
 }
Ejemplo n.º 7
0
        private NewArrayExpression NewArrayExpression(ExpressionType nodeType, System.Type type, JObject obj)
        {
            var elementType = this.Prop(obj, "elementType", this.Type);
            var expressions = this.Prop(obj, "expressions", this.Enumerable(this.Expression));

            switch (nodeType)
            {
            case ExpressionType.NewArrayInit:
                return(Expr.NewArrayInit(elementType, expressions));

            case ExpressionType.NewArrayBounds:
                return(Expr.NewArrayBounds(elementType, expressions));

            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 8
0
        void OverflowIntoParams(List <Argument> arguments, ParameterInfo[] parameters)
        {
            if (arguments.Count == 0 || parameters.Length == 0)
            {
                return;
            }

            var overflowingArgs = arguments.Skip(parameters.Length - 1).ToList();
            var lastParam       = parameters.Last();

            if (overflowingArgs.Count == 1 && overflowingArgs[0].Type == lastParam.ParameterType)
            {
                return;
            }

            Expr argExpr;

            if (lastParam.IsParams())
            {
                var elementType = lastParam.ParameterType.GetElementType();
                if (overflowingArgs.Any(arg => arg.Type != elementType && !arg.Type.IsSubclassOf(elementType)))
                {
                    return;
                }

                argExpr = Expr.NewArrayInit(
                    elementType,
                    overflowingArgs.Select(arg => Expr.Convert(arg.Expression, elementType)));
            }
            else if (lastParam.ParameterType == typeof(Varargs))
            {
                argExpr = Expr.New(
                    MemberInfos.NewVarargs,
                    Expr.NewArrayInit(
                        typeof(object),
                        overflowingArgs.Select(arg => Expr.Convert(arg.Expression, typeof(object)))));
            }
            else
            {
                return;
            }

            arguments.RemoveRange(arguments.Count - overflowingArgs.Count, overflowingArgs.Count);
            arguments.Add(new Argument(argExpr, lastParam.ParameterType));
        }
Ejemplo n.º 9
0
        static ExpressionBase CreateInvokeExpression(string funcName, IReadOnlyCollection <ExpressionBase> args)
        {
            var lambda   = RegisterDelegates[funcName];
            var argTypes = lambda.GetType().GetMethod("Invoke").GetParameters();

            if (argTypes.Length == 0 || argTypes[0].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length == 0)
            {
                if (lambda.Method.GetParameters().Length != args.Count)
                {
                    throw new InvalidOperationException($"函数{funcName}的参数数量不匹配。");
                }
            }
            else
            {
                args = new[] { ExpressionBase.NewArrayInit(typeof(object), args) };
            }
            var lambdaExpr = ExpressionBase.Constant(lambda);

            return(ExpressionBase.Invoke(lambdaExpr, args));
        }
Ejemplo n.º 10
0
        public static System.Linq.Expressions.Expression <Func <object[], object> > CreateComplexExpression(string p = null)
        {
            var stateParamExpr = SysExpr.Parameter(typeof(object[]), p);

            var expr = SysExpr.Lambda <Func <object[], object> >(
                SysExpr.MemberInit(
                    SysExpr.New(_ctorOfA,
                                SysExpr.New(_ctorOfB),
                                SysExpr.Convert(SysExpr.ArrayIndex(stateParamExpr, SysExpr.Constant(11)), typeof(string)),
                                SysExpr.NewArrayInit(typeof(ID),
                                                     SysExpr.New(_ctorOfD1),
                                                     SysExpr.New(_ctorOfD2))),
                    SysExpr.Bind(_propAProp,
                                 SysExpr.New(_ctorOfP,
                                             SysExpr.New(_ctorOfB))),
                    SysExpr.Bind(_fieldABop,
                                 SysExpr.New(_ctorOfB))),
                stateParamExpr);

            return(expr);
        }
Ejemplo n.º 11
0
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            Assert.NotNull(metaBuilder, args, name);

            // 2 implicit args: self, block
            var argsBuilder = new ArgsBuilder(2, _mandatoryParamCount, _optionalParamCount, _hasUnsplatParameter);

            argsBuilder.SetImplicit(0, AstFactory.Box(args.TargetExpression));
            argsBuilder.SetImplicit(1, args.Signature.HasBlock ? AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)) : AstFactory.NullOfProc);
            argsBuilder.AddCallArguments(metaBuilder, args);

            if (metaBuilder.Error)
            {
                return;
            }

            // box explicit arguments:
            var boxedArguments = argsBuilder.GetArguments();

            for (int i = 2; i < boxedArguments.Length; i++)
            {
                boxedArguments[i] = AstFactory.Box(boxedArguments[i]);
            }

            if (_method.GetType() == ParamsArrayDelegateType)
            {
                // Func<object, Proc, object[], object>
                metaBuilder.Result = AstFactory.CallDelegate(_method, new[] {
                    boxedArguments[0],
                    boxedArguments[1],
                    Ast.NewArrayInit(typeof(object), ArrayUtils.ShiftLeft(boxedArguments, 2))
                });
            }
            else
            {
                metaBuilder.Result = AstFactory.CallDelegate(_method, boxedArguments);
            }
        }
        protected override ExpressionBody Transform(ArrayExpression ax)
        {
            var elements = new List <ExpressionBody>(ax.Elements.Length);
            var i        = 0;

            for (; i < ax.Elements.Length; ++i)
            {
                var element = ax.Elements[i];
                if (element is ItemElement item)
                {
                    elements.Add(Transform(item.Value));
                }
                else
                {
                    break;
                }
            }

            var arr       = LX.NewArrayInit(typeof(LogEventPropertyValue), elements.ToArray());
            var collected = LX.Call(CollectSequenceElementsMethod, arr);

            for (; i < ax.Elements.Length; ++i)
            {
                var element = ax.Elements[i];
                if (element is ItemElement item)
                {
                    collected = LX.Call(ExtendSequenceValueWithItemMethod, collected, Transform(item.Value));
                }
                else
                {
                    var spread = (SpreadElement)element;
                    collected = LX.Call(ExtendSequenceValueWithSpreadMethod, collected, Transform(spread.Content));
                }
            }

            return(LX.Call(ConstructSequenceValueMethod, collected));
        }
        public LambdaExpression CreateLambda(Type from, Type to)
        {
            var input          = Ex.Parameter(from, "input");
            var eType          = to.GetElementType();
            var res            = Ex.Parameter(typeof(ConversionResult <>).MakeGenericType(eType).MakeArrayType(), "res");
            var end            = Ex.Label(typeof(ConversionResult <>).MakeGenericType(to), "end");
            var fromParameters = from.GetTypeInfo().GenericTypeArguments;
            var converters     = fromParameters.Select(t => new { Lambda = Ref.GetLambda(t, eType), Input = t }).ToArray();

            var block = Ex.Block(new[] { res },
                                 Ex.Assign(res, Ex.NewArrayBounds(typeof(ConversionResult <>).MakeGenericType(eType), Ex.Constant(fromParameters.Length))),
                                 Ex.Block(converters.Select((con, i) =>
                                                            Ex.Block(
                                                                Ex.Assign(Ex.ArrayAccess(res, Ex.Constant(i)), con.Lambda.ApplyTo(Ex.PropertyOrField(input, $"Item{i + 1}"))),
                                                                Ex.IfThen(Ex.Not(Ex.Property(Ex.ArrayIndex(res, Ex.Constant(i)), nameof(IConversionResult.IsSuccessful))),
                                                                          Ex.Goto(end, NoResult(to)))))),
                                 Ex.Label(end, Result(to,
                                                      Ex.NewArrayInit(eType,
                                                                      Enumerable.Range(0, fromParameters.Length)
                                                                      .Select(idx => Ex.Property(Ex.ArrayIndex(res, Ex.Constant(idx)), nameof(IConversionResult.Result)))))));
            var lambda = Ex.Lambda(block, input);

            return(lambda);
        }
        protected override ExpressionBody Transform(ObjectExpression ox)
        {
            var names  = new List <string>();
            var values = new List <ExpressionBody>();

            var i = 0;

            for (; i < ox.Members.Length; ++i)
            {
                var member = ox.Members[i];
                if (member is PropertyMember property)
                {
                    if (names.Contains(property.Name))
                    {
                        var oldPos = names.IndexOf(property.Name);
                        values[oldPos] = Transform(property.Value);
                    }
                    else
                    {
                        names.Add(property.Name);
                        values.Add(Transform(property.Value));
                    }
                }
                else
                {
                    break;
                }
            }

            var namesConstant = LX.Constant(names.ToArray(), typeof(string[]));
            var valuesArr     = LX.NewArrayInit(typeof(LogEventPropertyValue), values.ToArray());
            var properties    = LX.Call(CollectStructurePropertiesMethod, namesConstant, valuesArr);

            if (i == ox.Members.Length)
            {
                // No spreads; more efficient than `Complete*` because erasure is not required.
                return(LX.Call(ConstructStructureValueMethod, properties));
            }

            for (; i < ox.Members.Length; ++i)
            {
                var member = ox.Members[i];
                if (member is PropertyMember property)
                {
                    properties = LX.Call(
                        ExtendStructureValueWithPropertyMethod,
                        properties,
                        LX.Constant(property.Name),
                        Transform(property.Value));
                }
                else
                {
                    var spread = (SpreadMember)member;
                    properties = LX.Call(
                        ExtendStructureValueWithSpreadMethod,
                        properties,
                        Transform(spread.Content));
                }
            }

            return(LX.Call(CompleteStructureValueMethod, properties));
        }
Ejemplo n.º 15
0
        static LambdaExpression ApplyMethodHandler(string functionName, LambdaExpression functionLambda, IFunctionExecutionHandler handler)
        {
            // public static int MyMethod(object arg0, int arg1) { ... }

            // becomes:

            // (the 'handler' object is captured and called mh)
            // public static int MyMethodWrapped(object arg0, int arg1)
            // {
            //    var fhArgs = new FunctionExecutionArgs("MyMethod", new object[] { arg0, arg1});
            //    int result = default(int);
            //    try
            //    {
            //        fh.OnEntry(fhArgs);
            //        if (fhArgs.FlowBehavior == FlowBehavior.Return)
            //        {
            //            result = (int)fhArgs.ReturnValue;
            //        }
            //        else
            //        {
            //             // Inner call
            //             result = MyMethod(arg0, arg1);
            //             fhArgs.ReturnValue = result;
            //             fh.OnSuccess(fhArgs);
            //             result = (int)fhArgs.ReturnValue;
            //        }
            //    }
            //    catch ( Exception ex )
            //    {
            //        fhArgs.Exception = ex;
            //        fh.OnException(fhArgs);
            //        // Makes no sense to me yet - I've removed this FlowBehavior enum value.
            //        // if (fhArgs.FlowBehavior == FlowBehavior.Continue)
            //        // {
            //        //     // Finally will run, but can't change return value
            //        //     // Should we assign result...?
            //        //     // So Default value will be returned....?????
            //        //     fhArgs.Exception = null;
            //        // }
            //        // else
            //        if (fhArgs.FlowBehavior == FlowBehavior.Return)
            //        {
            //            // Clear the Exception and return the ReturnValue instead
            //            // Finally will run, but can't further change return value
            //            fhArgs.Exception = null;
            //            result = (int)fhArgs.ReturnValue;
            //        }
            //        else if (fhArgs.FlowBehavior == FlowBehavior.ThrowException)
            //        {
            //            throw fhArgs.Exception;
            //        }
            //        else // if (fhArgs.FlowBehavior == FlowBehavior.Default || fhArgs.FlowBehavior == FlowBehavior.RethrowException)
            //        {
            //            throw;
            //        }
            //    }
            //    finally
            //    {
            //        fh.OnExit(fhArgs);
            //        // NOTE: fhArgs.ReturnValue is not used again here...!
            //    }
            //
            //    return result;
            //  }
            // }

            // CONSIDER: There are some helpers in .NET to capture the exception context, which would allow us to preserve the stack trace in a fresh throw.

            // Ensure the handler object is captured.
            var mh       = Expression.Constant(handler);
            var funcName = Expression.Constant(functionName);

            // Prepare the functionHandlerArgs that will be threaded through the handler,
            // and a bunch of expressions that access various properties on it.
            var fhArgs              = Expr.Variable(typeof(FunctionExecutionArgs), "fhArgs");
            var fhArgsReturnValue   = SymbolExtensions.GetProperty(fhArgs, (FunctionExecutionArgs mea) => mea.ReturnValue);
            var fhArgsException     = SymbolExtensions.GetProperty(fhArgs, (FunctionExecutionArgs mea) => mea.Exception);
            var fhArgsFlowBehaviour = SymbolExtensions.GetProperty(fhArgs, (FunctionExecutionArgs mea) => mea.FlowBehavior);

            // Set up expressions to call the various handler methods.
            // TODO: Later we can determine which of these are actually implemented, and only write out the code needed in the particular case.
            var onEntry     = Expr.Call(mh, SymbolExtensions.GetMethodInfo <IFunctionExecutionHandler>(meh => meh.OnEntry(null)), fhArgs);
            var onSuccess   = Expr.Call(mh, SymbolExtensions.GetMethodInfo <IFunctionExecutionHandler>(meh => meh.OnSuccess(null)), fhArgs);
            var onException = Expr.Call(mh, SymbolExtensions.GetMethodInfo <IFunctionExecutionHandler>(meh => meh.OnException(null)), fhArgs);
            var onExit      = Expr.Call(mh, SymbolExtensions.GetMethodInfo <IFunctionExecutionHandler>(meh => meh.OnExit(null)), fhArgs);

            // Create the new parameters for the wrapper
            var outerParams = functionLambda.Parameters.Select(p => Expr.Parameter(p.Type, p.Name)).ToArray();
            // Create the array of parameter values that will be put into the method handler args.
            var paramsArray = Expr.NewArrayInit(typeof(object), outerParams.Select(p => Expr.Convert(p, typeof(object))));

            // Prepare the result and ex(ception) local variables
            var result = Expr.Variable(functionLambda.ReturnType, "result");
            var ex     = Expression.Parameter(typeof(Exception), "ex");

            // A bunch of helper expressions:
            // : new FunctionExecutionArgs(new object[] { arg0, arg1 })
            var fhArgsConstr = typeof(FunctionExecutionArgs).GetConstructor(new[] { typeof(string), typeof(object[]) });
            var newfhArgs    = Expr.New(fhArgsConstr, funcName, paramsArray);
            // : result = (int)fhArgs.ReturnValue
            var resultFromReturnValue = Expr.Assign(result, Expr.Convert(fhArgsReturnValue, functionLambda.ReturnType));
            // : fhArgs.ReturnValue = (object)result
            var returnValueFromResult = Expr.Assign(fhArgsReturnValue, Expr.Convert(result, typeof(object)));
            // : result = function(arg0, arg1)
            var resultFromInnerCall = Expr.Assign(result, Expr.Invoke(functionLambda, outerParams));

            // Build the Lambda wrapper, with the original parameters
            var lambda = Expr.Lambda(
                Expr.Block(new[] { fhArgs, result },
                           Expr.Assign(fhArgs, newfhArgs),
                           Expr.Assign(result, Expr.Default(result.Type)),
                           Expr.TryCatchFinally(
                               Expr.Block(
                                   onEntry,
                                   Expr.IfThenElse(
                                       Expr.Equal(fhArgsFlowBehaviour, Expr.Constant(FlowBehavior.Return)),
                                       resultFromReturnValue,
                                       Expr.Block(
                                           resultFromInnerCall,
                                           returnValueFromResult,
                                           onSuccess,
                                           resultFromReturnValue))),
                               onExit, // finally
                               Expr.Catch(ex,
                                          Expr.Block(
                                              Expr.Assign(fhArgsException, ex),
                                              onException,
                                              Expr.IfThenElse(
                                                  Expr.Equal(fhArgsFlowBehaviour, Expr.Constant(FlowBehavior.Return)),
                                                  Expr.Block(
                                                      Expr.Assign(fhArgsException, Expr.Constant(null, typeof(Exception))),
                                                      resultFromReturnValue),
                                                  Expr.IfThenElse(
                                                      Expr.Equal(fhArgsFlowBehaviour, Expr.Constant(FlowBehavior.ThrowException)),
                                                      Expr.Throw(fhArgsException),
                                                      Expr.Rethrow()))))
                               ),
                           result),
                functionName,
                outerParams);

            return(lambda);
        }
Ejemplo n.º 16
0
 public override SysExpr ToExpression() => NodeType == ExpressionType.NewArrayInit
 // ReSharper disable once AssignNullToNotNullAttribute
     ? SysExpr.NewArrayInit(Type.GetElementType(), ArgumentsToExpressions())
 // ReSharper disable once AssignNullToNotNullAttribute
     : SysExpr.NewArrayBounds(Type.GetElementType(), ArgumentsToExpressions());
        private static Func <object, Task> MakeLifecycleDisableFunc(Type type, string name)
        {
            var disableMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                                 .Select(m => (m, attrs: m.GetCustomAttributes(typeof(IEdgeLifecycleAttribute), false)))
                                 .Select(t => (t.m, attrs: t.attrs.Cast <IEdgeLifecycleAttribute>()))
                                 .Where(t => t.attrs.Any(a => a.Type == EdgeLifecycleType.Disable))
                                 .Select(t => t.m).ToArray();

            if (disableMethods.Length == 0)
            {
                Logger.loader.Notice($"Plugin {name} has no methods marked [OnExit] or [OnDisable]. Is this intentional?");
                return(o => TaskEx.WhenAll());
            }

            var taskMethods    = new List <MethodInfo>();
            var nonTaskMethods = new List <MethodInfo>();

            foreach (var m in disableMethods)
            {
                if (m.GetParameters().Length > 0)
                {
                    throw new InvalidOperationException($"Method {m} on {type.FullName} is marked [OnExit] or [OnDisable] and has parameters.");
                }
                if (m.ReturnType != typeof(void))
                {
                    if (typeof(Task).IsAssignableFrom(m.ReturnType))
                    {
                        taskMethods.Add(m);
                        continue;
                    }
                    else
                    {
                        Logger.loader.Warn($"Method {m} on {type.FullName} is marked [OnExit] or [OnDisable] and returns a non-Task value. It will be ignored.");
                    }
                }

                nonTaskMethods.Add(m);
            }

            Expression <Func <Task> > completedTaskDel = () => TaskEx.WhenAll();
            var getCompletedTask = completedTaskDel.Body;
            var taskWhenAll      = typeof(TaskEx).GetMethod(nameof(TaskEx.WhenAll), new[] { typeof(Task[]) });

            var objParam   = Expression.Parameter(typeof(object), "obj");
            var instVar    = ExpressionEx.Variable(type, "inst");
            var createExpr = Expression.Lambda <Func <object, Task> >(
                ExpressionEx.Block(new[] { instVar },
                                   nonTaskMethods
                                   .Select(m => (Expression)Expression.Call(instVar, m))
                                   .Prepend(ExpressionEx.Assign(instVar, Expression.Convert(objParam, type)))
                                   .Append(
                                       taskMethods.Count == 0
                                ? getCompletedTask
                                : Expression.Call(taskWhenAll,
                                                  Expression.NewArrayInit(typeof(Task),
                                                                          taskMethods.Select(m =>
                                                                                             (Expression)Expression.Convert(Expression.Call(instVar, m), typeof(Task))))))),
                objParam);

            return(createExpr.Compile());
        }
Ejemplo n.º 18
0
 public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers)
 {
     return(Expression.NewArrayInit(type, (IEnumerable <Expression>)initializers));
 }
Ejemplo n.º 19
0
        Exp ParseUnit(List <Token> expr)
        {
            Token tok;

            if (expr.Count == 0)
            {
                return(NoneExp);
            }

            else if (expr.Count == 1)
            {
                tok = expr[0];

                switch (tok.Type)
                {
                case TokenType.Identifier:
                    // keywords
                    switch (tok.Value)
                    {
                    case "None":
                        return(NoneExp);

                    case "True":
                        return(TrueExp);

                    case "False":
                        return(FalseExp);
                    }
                    // user identifiers
                    if (Local != null && Local.TryGetValue(tok.Value, out Exp value))
                    {
                        return(value);
                    }
                    else
                    {
                        return(GlobalAccess(tok.Value));
                    }

                case TokenType.Number:
                    if (int.TryParse(tok.Value, out int i))
                    {
                        return(Exp.Constant(new Int(i), Any));
                    }

                    else if (double.TryParse(tok.Value, out double d))
                    {
                        return(Exp.Constant(new Float(d), Any));
                    }

                    break;

                case TokenType.String:
                    return(Exp.Constant(new String(tok.Value), Any));

                case TokenType.Parenthesis:
                {
                    var w = Split(tok.Subset, TokenType.Comma);

                    if (w.Count == 1)         // parenthesis
                    {
                        return(Parse(w[0]));
                    }

                    // tuple

                    if (w.Count == 0)
                    {
                        return(Exp.New(typeof(Tuple)));
                    }
                    else
                    {
                        return(Exp.New(typeof(Tuple).GetConstructor(new[] { typeof(Object[]) }),
                                       Exp.NewArrayInit(typeof(Object), w.Select(Parse))));
                    }
                }

                case TokenType.Brackets:
                {
                    var w = Split(tok.Subset, TokenType.Comma);

                    if (w.Count == 0)
                    {
                        return(Exp.New(typeof(List)));
                    }
                    else
                    {
                        return(Exp.New(typeof(List).GetConstructor(new[] { typeof(Object[]) }),
                                       Exp.NewArrayInit(typeof(Object), w.Select(Parse))));
                    }
                }

                case TokenType.Braces:
                {
                    var w = Split(tok.Subset, TokenType.Comma);

                    if (Contains(w[0], TokenType.Colon))
                    {
                        // dict
                        if (w.Count == 0)
                        {
                            return(Exp.New(typeof(Dict)));
                        }
                        else
                        {
                            var items = new List <ElementInit>();
                            var adder = typeof(Dictionary <Object, Object>).GetMethod("Add");

                            foreach (var v in w)
                            {
                                var row   = Split(v, TokenType.Colon);
                                var left  = Parse(row[0]);
                                var right = Parse(row[1]);
                                items.Add(Exp.ElementInit(adder, left, right));
                            }

                            return(Exp.New(typeof(Dict).GetConstructor(new[] { typeof(Dictionary <Object, Object>) }),
                                           Exp.ListInit(Exp.New(typeof(Dictionary <Object, Object>)), items)));
                        }
                    }
                    else
                    {
                        // set
                        if (w.Count == 0)
                        {
                            return(Exp.New(typeof(Set)));
                        }
                        else
                        {
                            return(Exp.New(typeof(Set).GetConstructor(new[] { typeof(Object[]) }),
                                           Exp.NewArrayInit(typeof(Object), w.Select(Parse))));
                        }
                    }
                }
                }
            }
            else // length > 1
            {
                tok = expr[0]; // starts

                if (tok.Type == TokenType.Operator)
                {
                    expr.RemoveAt(0);
                    Exp obj = ParseUnit(expr);

                    switch (tok.op)
                    {
                    case Op.Invert:
                        return(Exp.Call(obj, typeof(Object).GetMethod("__invert__")));

                    case Op.Add:
                        return(Exp.Call(obj, typeof(Object).GetMethod("__pos__")));

                    case Op.Subtract:
                        return(Exp.Call(obj, typeof(Object).GetMethod("__neg__")));

                    case Op.Not:
                        return(Exp.Call(obj, typeof(Object).GetMethod("__not__")));

                    default:
                        throw new Exception("invalid unary operator");
                    }
                }

                tok = expr[^ 1]; // ends