Пример #1
0
        public IParseItem Visit(IndexerItem target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            target.Prefix.Accept(this);
            target.Expression.Accept(this);

            return(target);
        }
Пример #2
0
        /// <summary>
        /// Called when the item is an indexer 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(IndexerItem target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            //! push {Prefix}.GetIndex({Expression})
            var gen = compiler.CurrentGenerator;

            target.Prefix.Accept(this);
            target.Expression.Accept(this);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.GetIndex)));

            return(target);
        }
Пример #3
0
        /// <summary>
        /// Assigns the values of the parse item to the given value.
        /// </summary>
        /// <param name="target">The item to assign the value to (e.g. NameItem).</param>
        /// <param name="local">Whether this is a local definition.</param>
        /// <param name="getIndex">A function to get the index of the object,
        /// pass null to use the default.</param>
        /// <param name="getValue">A function to get the value to set to.</param>
        void AssignValue(IParseItem target, bool local, Action getIndex, Action getValue)
        {
            ILGenerator gen = compiler.CurrentGenerator;

            ChunkBuilder.VarDefinition field;
            if (local)
            {
                field = compiler.DefineLocal((NameItem)target);
            }
            else if (target is IndexerItem)
            {
                IndexerItem name = (IndexerItem)target;
                // {name.Prefix}.SetIndex({name.Expression}, value);
                name.Prefix.Accept(this);
                if (getIndex != null)
                {
                    getIndex();
                }
                else
                {
                    name.Expression.Accept(this);
                }
                getValue();
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.SetIndex)));
                return;
            }
            else // names[i] is NameItem
            {
                NameItem item = (NameItem)target;
                field = compiler.FindVariable(item);
            }

            // envField = value;
            field.StartSet();
            getValue();
            field.EndSet();
        }
Пример #4
0
        /// <summary>
        /// Called when the item is a function definition 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(FuncDefItem target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            var gen = compiler.CurrentGenerator;

            ChunkBuilder.VarDefinition field = null;
            string name  = null;
            bool   store = false;

            if (target.Local)
            {
                // local function definition.
                if (target.InstanceName != null)
                {
                    throw new SyntaxException(Resources.InstanceLocalMethod, target.Debug);
                }
                if (!(target.Prefix is NameItem))
                {
                    throw new SyntaxException(Resources.IndexerLocalMethod, target.Debug);
                }

                NameItem namei = (NameItem)target.Prefix;
                name  = namei.Name;
                field = compiler.DefineLocal(namei);
                field.StartSet();
            }
            else if (target.Prefix != null)
            {
                if (target.InstanceName != null)
                {
                    // instance function definition.
                    name = null;
                    if (target.Prefix is NameItem)
                    {
                        name = ((NameItem)target.Prefix).Name;
                    }
                    else
                    {
                        name = (string)((LiteralItem)((IndexerItem)target.Prefix).Expression).Value;
                    }
                    name += ":" + target.InstanceName;

                    // {Prefix}.SetIndex({InstanceName}, {ImplementFunction(..)})
                    target.Prefix.Accept(this);
                    gen.Emit(OpCodes.Ldarg_1);
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod());
                    gen.Emit(OpCodes.Ldstr, target.InstanceName);
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateValue)));
                    store = true;
                }
                else if (target.Prefix is IndexerItem)
                {
                    // global function definition with indexer
                    // {Prefix}.SetIndex({Expression}, {ImplementFunction(..)})
                    IndexerItem index = (IndexerItem)target.Prefix;
                    name = (string)((LiteralItem)index.Expression).Value;
                    index.Prefix.Accept(this);
                    index.Expression.Accept(this);
                    store = true;
                }
                else
                {
                    // global function definition with name
                    name  = ((NameItem)target.Prefix).Name;
                    field = compiler.FindVariable((NameItem)target.Prefix);
                    field.StartSet();
                }
            }

            compiler.ImplementFunction(this, target, name);

            if (field != null)
            {
                field.EndSet();
            }
            else if (store)
            {
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.SetIndex)));
            }

            return(target);
        }
Пример #5
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(nameof(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).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod());
                gen.Emit(OpCodes.Ldstr, target.InstanceName);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateValue)));
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.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(nameof(LuaNil.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);
                if (i + 1 == target.Arguments.Count && target.IsLastArgSingle)
                {
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.Single)));
                }
                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).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod());
            gen.Emit(OpCodes.Ldloc, args);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.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(nameof(ILuaValue.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);
        }
Пример #6
0
        /// <summary>
        /// Called when the item is an assignment 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(AssignmentItem target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            ILGenerator gen = compiler.CurrentGenerator;

            // ILuaValue[] loc = new ILuaValue[{target.Expressions.Count}];
            LocalBuilder loc = compiler.CreateArray(typeof(ILuaValue), target.Expressions.Count);
            // ILuaValue[] names = new ILuaValue[{target.Names.Count}];
            LocalBuilder names = compiler.CreateArray(typeof(ILuaValue), target.Names.Count);

            // have to evaluate the name indexer expressions before
            //   setting the values otherwise the following will fail:
            // i, t[i] = i+1, 20
            for (int i = 0; i < target.Names.Count; i++)
            {
                if (target.Names[i] is IndexerItem)
                {
                    IndexerItem item = (IndexerItem)target.Names[i];
                    gen.Emit(OpCodes.Ldloc, names);
                    gen.Emit(OpCodes.Ldc_I4, i);
                    item.Expression.Accept(this);
                    gen.Emit(OpCodes.Stelem, typeof(ILuaValue));
                }
            }

            for (int i = 0; i < target.Expressions.Count; i++)
            {
                // loc[{i}] = {exps[i]};
                gen.Emit(OpCodes.Ldloc, loc);
                gen.Emit(OpCodes.Ldc_I4, i);
                target.Expressions[i].Accept(this);
                if (i + 1 == target.Expressions.Count && target.IsLastExpressionSingle)
                {
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.Single)));
                }
                gen.Emit(OpCodes.Stelem, typeof(ILuaValue));
            }

            // ILuaMultiValue exp = E.Runtime.CreateMultiValue(loc);
            LocalBuilder exp = compiler.CreateTemporary(typeof(ILuaMultiValue));

            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod());
            gen.Emit(OpCodes.Ldloc, loc);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateMultiValue)));
            gen.Emit(OpCodes.Stloc, exp);
            compiler.RemoveTemporary(loc);

            for (int i = 0; i < target.Names.Count; i++)
            {
                AssignValue(target.Names[i], target.Local,
                            !(target.Names[i] is IndexerItem) ? (Action)null : () =>
                {
                    // only called if the target object is an indexer item.

                    // $index = names[{i}];
                    gen.Emit(OpCodes.Ldloc, names);
                    gen.Emit(OpCodes.Ldc_I4, i);
                    gen.Emit(OpCodes.Ldelem, typeof(ILuaValue));
                },
                            () =>
                {
                    // $value = exp[{i}];
                    gen.Emit(OpCodes.Ldloc, exp);
                    gen.Emit(OpCodes.Ldc_I4, i);
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaMultiValue).GetMethod("get_Item"));
                });
            }
            compiler.RemoveTemporary(exp);
            compiler.RemoveTemporary(names);

            return(target);
        }
Пример #7
0
        /// <summary>
        /// Reads a function from the input.  Input must be on the word 'function'.  If canName is true,
        /// it will give the function the read name; otherwise it will give it a null name.
        /// </summary>
        /// <param name="input">Where to read input from.</param>
        /// <param name="canName">True if the function can have a name, otherwise false.</param>
        /// <param name="local">True if this function is a local definition, otherwise false.</param>
        /// <returns>The function definition that was read.</returns>
        protected virtual FuncDefItem _readFunctionHelper(Lexer input, bool canName, bool local)
        {
            Token debug = input.Expect(TokenType.Function);

            IParseVariable name     = null;
            string         instName = null;

            if (input.PeekType(TokenType.Identifier))
            {
                Token temp = input.Expect(TokenType.Identifier);
                name = new NameItem(temp.Value)
                {
                    Debug = temp
                };
                while (input.ReadIfType(TokenType.Indexer))
                {
                    temp = input.Expect(TokenType.Identifier);
                    var literal = new LiteralItem(temp.Value)
                    {
                        Debug = temp
                    };
                    name = new IndexerItem(name, literal)
                    {
                        Debug = name.Debug
                    };
                }

                if (input.ReadIfType(TokenType.Colon))
                {
                    instName = input.Expect(TokenType.Identifier).Value;
                }
            }
            if (name != null && !canName)
            {
                throw new SyntaxException(Resources.FunctionCantHaveName, input.Name, debug);
            }
            if (name == null && canName)
            {
                throw new SyntaxException("Function statements must provide name", input.Name, debug);
            }

            var args = new List <NameItem>();

            input.Expect(TokenType.BeginParen);
            if (!input.PeekType(TokenType.EndParen))
            {
                do
                {
                    Token temp = input.PeekType(TokenType.Elipsis) ?
                                 input.Expect(TokenType.Elipsis) :
                                 input.Expect(TokenType.Identifier);
                    args.Add(new NameItem(temp.Value)
                    {
                        Debug = temp
                    });
                    if (temp.Value == "...")
                    {
                        break;
                    }
                } while (input.ReadIfType(TokenType.Comma));
            }
            input.Expect(TokenType.EndParen);
            BlockItem chunk = _readBlock(input);

            input.Expect(TokenType.End);
            chunk.Return ??= new ReturnItem();

            return(new FuncDefItem(args.ToArray(), chunk)
            {
                Debug = debug,
                InstanceName = instName,
                Prefix = name,
                Local = local,
            });
        }
Пример #8
0
        /// <summary>
        /// Reads a prefix-expression from the input.
        /// </summary>
        /// <param name="input">The input to read from.</param>
        /// <returns>The parsed expression.</returns>
        protected virtual IParseExp _readPrefixExp(Lexer input, out bool isParentheses)
        {
            Token     debug = input.Peek();
            IParseExp ret;

            if (input.ReadIfType(TokenType.BeginParen))
            {
                isParentheses = true;
                ret           = _readExp(input, out _);
                input.Expect(TokenType.EndParen);
            }
            else
            {
                isParentheses = false;
                Token name = input.Expect(TokenType.Identifier);
                ret = new NameItem(name.Value)
                {
                    Debug = name
                };
            }

            while (true)
            {
                if (input.ReadIfType(TokenType.BeginBracket))
                {
                    isParentheses = false;
                    IParseExp temp = _readExp(input, out _);
                    ret = new IndexerItem(ret, temp)
                    {
                        Debug = debug
                    };
                    input.Expect(TokenType.EndBracket);
                }
                else if (input.ReadIfType(TokenType.Indexer))
                {
                    isParentheses = false;
                    Token token = input.Expect(TokenType.Identifier);
                    var   name  = new LiteralItem(token.Value)
                    {
                        Debug = token
                    };
                    ret = new IndexerItem(ret, name)
                    {
                        Debug = debug
                    };
                }
                else
                {
                    string instName = null;
                    int    overload = -1;
                    if (input.ReadIfType(TokenType.Colon))
                    {
                        instName = input.Expect(TokenType.Identifier).Value;
                        int idx = instName.IndexOf('`');
                        if (idx >= 0)
                        {
                            if (!int.TryParse(instName.Substring(idx + 1), out overload))
                            {
                                throw input.SyntaxError(Resources.OnlyNumbersInOverload);
                            }
                            instName = instName.Substring(0, idx);
                        }
                    }
                    else if (ret is NameItem name)
                    {
                        int idx = name.Name.IndexOf('`');
                        if (idx >= 0)
                        {
                            if (!int.TryParse(name.Name.Substring(idx + 1), out overload))
                            {
                                throw input.SyntaxError(Resources.OnlyNumbersInOverload);
                            }
                            name.Name = name.Name.Substring(0, idx);
                        }
                    }

                    bool isLastSingle = false;
                    var  args         = new List <FuncCallItem.ArgumentInfo>();
                    if (input.PeekType(TokenType.BeginTable))
                    {
                        args.Add(new FuncCallItem.ArgumentInfo(_readTable(input), false));
                    }
                    else if (input.PeekType(TokenType.StringLiteral))
                    {
                        Token token = input.Expect(TokenType.StringLiteral);
                        args.Add(new FuncCallItem.ArgumentInfo(new LiteralItem(token.Value)
                        {
                            Debug = token
                        },
                                                               false));
                    }
                    else if (input.ReadIfType(TokenType.BeginParen))
                    {
                        if (!input.PeekType(TokenType.EndParen))
                        {
                            do
                            {
                                bool isRef      = input.ReadIfType(TokenType.Ref);
                                bool isRefParen = false;
                                if (isRef)
                                {
                                    isRefParen = input.ReadIfType(TokenType.BeginParen);
                                }
                                else
                                {
                                    isRef = input.ReadIfType(TokenType.RefSymbol);
                                }

                                args.Add(new FuncCallItem.ArgumentInfo(_readExp(input, out isLastSingle), isRef));
                                if (isRefParen)
                                {
                                    input.Expect(TokenType.EndParen);
                                }
                            } while (input.ReadIfType(TokenType.Comma));
                        }
                        input.Expect(TokenType.EndParen);
                    }
                    else
                    {
                        break;
                    }
                    isParentheses = false;
                    ret           = new FuncCallItem(ret, args.ToArray())
                    {
                        Debug           = debug,
                        InstanceName    = instName,
                        Overload        = overload,
                        IsLastArgSingle = isLastSingle,
                    };
                }
            }
            return(ret);
        }