Пример #1
0
        /// <summary>
        /// Called when the item is a function call item.
        /// </summary>
        /// <param name="target">The object that was passed to IParseItem.Visit.</param>
        /// <returns>The passed target or a modification of it.</returns>
        /// <exception cref="System.ArgumentNullException">If target is null.</exception>
        public IParseItem Visit(FuncCallItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            //// load the args into an array.
            ILGenerator gen = compiler.CurrentGenerator;
            LocalBuilder f = compiler.CreateTemporary(typeof(ILuaValue));
            LocalBuilder self = compiler.CreateTemporary(typeof(object));

            /* add 'self' if instance call */
            if (target.InstanceName != null)
            {
                // self = {Prefix};
                target.Prefix.Accept(this);
                gen.Emit(OpCodes.Stloc, self);
                    
                // f = self.GetIndex(temp);
                gen.Emit(OpCodes.Ldloc, self);
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetMethod("get_Runtime"));
                gen.Emit(OpCodes.Ldstr, target.InstanceName);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("CreateValue"));
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("GetIndex"));
                gen.Emit(OpCodes.Stloc, f);
            }
            else if (target.Prefix is IndexerItem)
            {
                // self = {Prefix};
                IndexerItem item = (IndexerItem)target.Prefix;
                item.Prefix.Accept(this);
                gen.Emit(OpCodes.Stloc, self);

                // Store the old value to restore later, add a dummy.
                var tempPrefix = item.Prefix;
                item.Prefix = new IndexerHelper(gen, self);

                // f = {Prefix};
                target.Prefix.Accept(this);
                gen.Emit(OpCodes.Stloc, f);

                // Restore the old value
                item.Prefix = tempPrefix;
            }
            else
            {
                // self = LuaNil.Nil;
                gen.Emit(OpCodes.Ldnull);
                gen.Emit(OpCodes.Ldfld, typeof(LuaNil).GetField("Nil", BindingFlags.Static | BindingFlags.Public));
                gen.Emit(OpCodes.Stloc, self);

                // f = {Prefix};
                target.Prefix.Accept(this);
                gen.Emit(OpCodes.Stloc, f);
            }

            // var args = new ILuaValue[...];
            LocalBuilder args = compiler.CreateArray(typeof(ILuaValue), target.Arguments.Count);
            for (int i = 0; i < target.Arguments.Count; i++)
            {
                // args[i] = {item};
                gen.Emit(OpCodes.Ldloc, args);
                gen.Emit(OpCodes.Ldc_I4, i);
                target.Arguments[i].Expression.Accept(this);
                gen.Emit(OpCodes.Stelem, typeof(ILuaValue));
            }
            
            // var rargs = E.Runtime.CreateMultiValue(args);
            var rargs = compiler.CreateTemporary(typeof(ILuaMultiValue));
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetMethod("get_Runtime"));
            gen.Emit(OpCodes.Ldloc, args);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("CreateMultiValue"));
            gen.Emit(OpCodes.Stloc, rargs);
            compiler.RemoveTemporary(args);

            //! push f.Invoke(self, {!!InstanceName}, {Overload}, rargs);
            gen.Emit(OpCodes.Ldloc, f);
            gen.Emit(OpCodes.Ldloc, self);
            gen.Emit(target.InstanceName != null ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            gen.Emit(OpCodes.Ldc_I4, target.Overload);
            gen.Emit(OpCodes.Ldloc, rargs);
            if (target.IsTailCall)
                gen.Emit(OpCodes.Tailcall);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("Invoke"));
            compiler.RemoveTemporary(f);
            compiler.RemoveTemporary(self);

            //! pop
            if (target.Statement)
                gen.Emit(OpCodes.Pop);

            // support byRef
            for (int i = 0; i < target.Arguments.Count; i++)
            {
                if (target.Arguments[i].IsByRef)
                {
                    AssignValue(target.Arguments[i].Expression, false, null,
                        () =>
                        {
                            // $value = rargs[{i}];
                            gen.Emit(OpCodes.Ldloc, rargs);
                            gen.Emit(OpCodes.Ldc_I4, i);
                            gen.Emit(OpCodes.Callvirt, typeof(ILuaMultiValue).GetMethod("get_Item"));
                        });
                }
            }
            compiler.RemoveTemporary(rargs);

            return target;
        }
Пример #2
0
        /// <summary>
        /// Called when the item is a function call item.
        /// </summary>
        /// <param name="target">The object that was passed to IParseItem.Visit.</param>
        /// <returns>The passed target or a modification of it.</returns>
        /// <exception cref="System.ArgumentNullException">If target is null.</exception>
        public IParseItem Visit(FuncCallItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            foreach (var item in target.Arguments)
                item.Expression.Accept(this);
            target.Prefix.Accept(this);

            return target;
        }
Пример #3
0
        /// <summary>
        /// Reads a prefix-expression from the input.
        /// </summary>
        /// <param name="input">Where to read input from.</param>
        /// <param name="token">The token to append the total token onto.</param>
        /// <returns>The expression that was read.</returns>
        protected virtual IParseExp ReadPrefixExp(ITokenizer input, ref Token token)
        {
            Stack<UnaryInfo> ex = new Stack<UnaryInfo>();
            IParseExp o = null;
            Token last, debug = input.Peek();
            debug.Value = "";

            // check for unary operators
            last = input.Peek();
            while (last.Value == "-" || last.Value == "not" || last.Value == "#")
            {
                Read(input, ref debug);

                if (last.Value == "-")
                {
                    ex.Push(new UnaryInfo(1, last.StartPos, last.StartLine));
                }
                else if (last.Value == "not")
                {
                    ex.Push(new UnaryInfo(2, last.StartPos, last.StartLine));
                }
                else
                {
                    Contract.Assert(last.Value == "#");
                    ex.Push(new UnaryInfo(3, last.StartPos, last.StartLine));
                }
                last = input.Peek();
            }

            // check for literals
            last = input.Peek();
            int over = -1;
            if (last.Value != null)
            {
                NumberFormatInfo ni = CultureInfo.CurrentCulture.NumberFormat;
                if (last.Value != "..." && (char.IsNumber(last.Value, 0) || last.Value.StartsWith(ni.NumberDecimalSeparator, StringComparison.CurrentCulture)))
                {
                    Read(input, ref debug); // read the number.
                    try
                    {
                        o = new LiteralItem(double.Parse(last.Value, CultureInfo.CurrentCulture)) { Debug = last };
                    }
                    catch (FormatException e)
                    {
                        throw new SyntaxException(Resources.BadNumberFormat, input.Name, last, e);
                    }
                }
                else if (last.Value.StartsWith("&", StringComparison.Ordinal))
                {
                    Read(input, ref debug);
                    try
                    {
                        o = new LiteralItem(Convert.ToDouble(long.Parse(last.Value.Substring(1),
                            NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture))) { Debug = last };
                    }
                    catch (FormatException e)
                    {
                        throw new SyntaxException(Resources.BadNumberFormat, input.Name, last, e);
                    }
                }
                else if (last.Value.StartsWith("\"", StringComparison.Ordinal))
                {
                    Read(input, ref debug);
                    o = new LiteralItem(last.Value.Substring(1)) { Debug = last };
                }
                else if (last.Value.StartsWith("{", StringComparison.Ordinal))
                {
                    o = ReadTable(input, ref debug);
                }
                else if (last.Value == "(")
                {
                    Read(input, ref debug);
                    o = ReadExp(input, ref debug);
                    last = Read(input, ref debug);
                    if (last.Value != ")")
                        throw new SyntaxException(string.Format(Resources.TokenInvalidExpecting, last.Value, "expression", ")"),
                            input.Name, last);
                }
                else if (last.Value == "true")
                {
                    Read(input, ref debug);
                    o = new LiteralItem(true) { Debug = last };
                }
                else if (last.Value == "false")
                {
                    Read(input, ref debug);
                    o = new LiteralItem(false) { Debug = last };
                }
                else if (last.Value == "nil")
                {
                    Read(input, ref debug);
                    o = new LiteralItem(null) { Debug = last };
                }
                else if (last.Value == "function")
                {
                    o = ReadFunctionHelper(input, ref debug, false, false);
                }
                else
                {
                    // allow for specifying overloads on global variables
                    if (last.Value.IndexOf('`') != -1)
                    {
                        if (!int.TryParse(last.Value.Substring(last.Value.IndexOf('`') + 1), out over))
                            throw new InvalidOperationException(Resources.OnlyNumbersInOverload);

                        last.Value = last.Value.Substring(0, last.Value.IndexOf('`'));
                    }

                    Read(input, ref debug);
                    o = new NameItem(last.Value) { Debug = last };
                }
            }

            // read function calls and indexers
            {
                string inst = null;
                bool cont = true;
                while (cont)
                {
                    last = input.Peek();
                    last.Value = last.Value ?? "";
                    if (last.Value == ".")
                    {
                        Read(input, ref debug);
                        if (over != -1)
                            throw new SyntaxException(Resources.FunctionCallAfterOverload, input.Name, last);
                        if (inst != null)
                            throw new SyntaxException(Resources.IndexerAfterInstance, input.Name, last);

                        last = Read(input, ref debug);

                        // allow for specifying an overload
                        if (last.Value.IndexOf('`') != -1)
                        {
                            if (!int.TryParse(last.Value.Substring(last.Value.IndexOf('`') + 1), out over))
                                throw new InvalidOperationException(Resources.OnlyNumbersInOverload);

                            last.Value = last.Value.Substring(0, last.Value.IndexOf('`'));
                        }

                        if (!IsName(last.Value))
                            throw new SyntaxException(string.Format(Resources.TokenNotAName, "indexer", last.Value),
                                input.Name, last);
                        if (!(o is IParsePrefixExp))
                            throw new SyntaxException(Resources.IndexAfterExpression, input.Name, last);

                        o = new IndexerItem(o, new LiteralItem(last.Value) { Debug = last }) { Debug = debug };
                    }
                    else if (last.Value == ":")
                    {
                        Read(input, ref debug);
                        if (over != -1)
                            throw new SyntaxException(Resources.FunctionCallAfterOverload, input.Name, last);
                        if (inst != null)
                            throw new SyntaxException(Resources.OneInstanceCall, input.Name, last);
                        inst = Read(input, ref debug).Value;
                        if (!IsName(inst))
                            throw new SyntaxException(string.Format(Resources.TokenNotAName, "indexer", last.Value),
                                input.Name, last);
                    }
                    else if (last.Value == "[")
                    {
                        Read(input, ref debug);
                        if (over != -1)
                            throw new SyntaxException(Resources.FunctionCallAfterOverload,
                                input.Name, last);
                        if (inst != null)
                            throw new SyntaxException(Resources.IndexerAfterInstance, input.Name, last);

                        var temp = ReadExp(input, ref debug);
                        last = Read(input, ref debug);
                        o = new IndexerItem(o, temp) { Debug = debug };
                        if (last.Value != "]")
                            throw new SyntaxException(
                                string.Format(Resources.TokenInvalidExpecting, last.Value, "indexer", "]"),
                                input.Name, last);
                    }
                    else if (last.Value.StartsWith("\"", StringComparison.Ordinal))
                    {
                        Read(input, ref debug);
                        FuncCallItem temp = new FuncCallItem(o, inst, over) { Debug = debug };
                        o = temp;
                        temp.AddItem(new LiteralItem(last.Value.Substring(1)), false);
                        inst = null;
                        over = -1;
                    }
                    else if (last.Value == "{")
                    {
                        var temp = ReadTable(input, ref debug);
                        FuncCallItem func = new FuncCallItem(o, inst, over) { Debug = debug };
                        o = func;
                        func.AddItem(temp, false);
                        inst = null;
                        over = -1;
                    }
                    else if (last.Value == "(")
                    {
                        Read(input, ref debug);
                        FuncCallItem func = new FuncCallItem(o, inst, over);
                        o = func;
                        inst = null;
                        over = -1;
                        while (input.Peek().Value != ")" && input.Peek().Value != null)
                        {
                            bool? byRef = null;
                            if (input.Peek().Value == "@")
                            {
                                byRef = false;
                                Read(input, ref debug);
                            }
                            else if (input.Peek().Value == "ref")
                            {
                                Read(input, ref debug);
                                if (input.Peek().Value == "(")
                                {
                                    Read(input, ref debug);
                                    byRef = true;
                                }
                                else
                                    byRef = false;
                            }

                            var temp = ReadExp(input, ref debug);
                            if (byRef != null && !(temp is NameItem) && !(temp is IndexerItem))
                                throw new SyntaxException(Resources.OnlyVarByReference, input.Name, last);
                            if (temp == null)
                                throw new SyntaxException(string.Format(Resources.InvalidDefinition, "function call"),
                                    input.Name, last);
                            func.AddItem(temp, byRef != null);

                            if (byRef == true && (last = input.Read()).Value != ")")
                                throw new SyntaxException(Resources.RefOneArgument,
                                    input.Name, last);

                            if (input.Peek().Value == ",")
                                Read(input, ref debug);
                            else if (input.Peek().Value == ")")
                                break;
                            else
                                throw new SyntaxException(string.Format(Resources.TokenInvalidExpecting2, input.Peek().Value, "function call", ",", ")"), input.Name, last);
                        }

                        if (input.Peek() == null)
                            throw new SyntaxException(string.Format(Resources.UnexpectedEOF, "function call"),
                                input.Name, last);
                        Read(input, ref debug);
                        func.Debug = debug;
                    }
                    else
                    {
                        if (inst != null)
                            throw new SyntaxException(Resources.InstanceMissingArgs, input.Name, last);
                        if (over != -1)
                            throw new SyntaxException(Resources.OverloadMissingArgs, input.Name, last);
                        cont = false;
                    }
                }
            }

            // read exponents
            // HACK: This is needed here because the power operator has
            //   higher precedence than the unary operators.  Rather than
            //   have unary operators handled in ReadExp, they are handled
            //   so exponents need to be handled before we apply the
            //   unary operators.
            if (input.Peek().Value == "^")
            {
                Read(input, ref debug);
                var temp = ReadPrefixExp(input, ref debug);
                BinOpItem item = new BinOpItem(o, BinaryOperationType.Power, temp) { Debug = debug };
                o = item;
            }

            // now apply the unary operators
            while (ex.Count > 0)
            {
                var loc = ex.Pop();
                Token tok = new Token(debug.Value, loc.StartPos, debug.EndPos, loc.StartLine, debug.EndLine);
                switch (loc.Version)
                {
                    case 1: // neg
                        if (o is LiteralItem)
                        {
                            object oo = (o as LiteralItem).Value;
                            if (!(oo is double))
                                throw new SyntaxException(Resources.InvalidUnary,
                                    input.Name, debug);

                            o = new LiteralItem(-(double)oo) { Debug = tok };
                        }
                        else
                            o = new UnOpItem(o, UnaryOperationType.Minus) { Debug = tok };
                        break;
                    case 2: // not
                        o = new UnOpItem(o, UnaryOperationType.Not) { Debug = tok };
                        break;
                    case 3: // len
                        o = new UnOpItem(o, UnaryOperationType.Length) { Debug = tok };
                        break;
                }
            }

            // finaly return
            token.Append(debug);
            return o;
        }