Exemple #1
0
        /// <summary>
        /// Adds a dependency to a .NET/CLR library using clr.load,
        /// then it sets type to the type in the assembly.
        /// </summary>
        /// <param name="c"></param>
        /// <param name="assembly"></param>
        /// <param name="type"></param>
        public static void AddClrDependency(Chunk c, string assembly, string type)
        {
            AddClrDependency(c, assembly);

            // Assignment with FunctionCall
            AssignmentStatement a = new AssignmentStatement();

            CallExpr call = new CallExpr();
            call.Scope = c.Scope;
            Variable require = c.Scope.GetVariable("clr");
            VariableExpression v = new VariableExpression();
            if (require == null)
            {
                require = c.Scope.CreateGlobal("clr");
                require.IsGlobal = true;
            }

            string name = "", varName = "";

            if (type.Contains('.'))
            {
                name = type.Substring(0, type.LastIndexOf('.'));
                varName = type.Substring(type.LastIndexOf('.') + 1);
            }
            else
            {
                name = assembly;
                varName = type;
            }

            v.Var = require;
            MemberExpr me = new MemberExpr();
            me.Base = v;
            me.Indexer = ".";
            me.Ident = "getns";
            call.Base = me;
            call.Arguments.Add(new StringExpr(name) { StringType = TokenType.DoubleQuoteString });
            a.IsLocal = true; // local import
            MemberExpr me2 = new MemberExpr();
            me2.Base = call;
            me2.Indexer = ".";
            me2.Ident = varName;
            a.Rhs.Add(me2);

            Variable var = c.Scope.GetVariable(varName);
            VariableExpression v2 = new VariableExpression();
            if (var == null)
            {
                var = c.Scope.CreateLocal(varName);
            }
            v2.Var = var;
            a.Lhs.Add(v2);

            // Insert after the load
            c.Body.Insert(1, a);
        }
Exemple #2
0
        void DoExpr(Expression e, bool setVar = false, int setVarLhsCount = -1, bool onlyCheckConsts = false)
        {
            if (e is AnonymousFunctionExpr) // function() ... end
            {
            }
            else if (e is BinOpExpr)
            {
                BinOpExpr boe = e as BinOpExpr;
                switch (boe.GetOperator())
                {
                    case BinaryOperator.Add:
                        binOp("ADD", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Subtract:
                        binOp("SUB", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Multiply:
                        binOp("MUL", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Divide:
                        binOp("DIV", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Power:
                        binOp("POW", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Modulus:
                        binOp("MOD", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.Concat:
                        binOp("CONCAT", boe.Lhs, boe.Rhs);
                        return;
                    case BinaryOperator.And:
                        break;
                    case BinaryOperator.Or:
                        break;
                    case BinaryOperator.LessThan:
                        break;
                    case BinaryOperator.LessThanOrEqualTo:
                        break;
                    case BinaryOperator.GreaterThan:
                        break;
                    case BinaryOperator.GreaterThanOrEqualTo:
                        break;
                    case BinaryOperator.NotEqual:
                        break;
                    case BinaryOperator.ShiftRight:
                        CallExpr ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "rshift",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.ShiftLeft:
                        ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "lshift",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.Xor:
                        ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "bxor",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.BitAnd:
                        ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "band",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.BitOr:
                        ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "bor",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.BitNot:
                        ce = new CallExpr();
                        ce.Arguments.Add(boe.Lhs);
                        ce.Arguments.Add(boe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "bnot",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case BinaryOperator.NONE:
                    default:
                        throw new Exception("Unknown binary operator '" + boe.Op + "'");
                }
            }
            else if (e is BoolExpr)
            {
                bool v = ((BoolExpr)e).Value;
                Instruction i = new Instruction("LOADBOOL");
                i.A = block.getreg();
                i.B = v ? 1 : 0;
                i.C = 0;
                emit(i);
                return;
            }
            else if (e is CallExpr)//&& (!(e is StringCallExpr) && !(e is TableCallExpr)))
            {
                CallExpr ce = e as CallExpr;
                int breg = ++block.regnum;
                DoExpr(ce.Base);
                bool isZero = false;
                bool isMethod = false;
                Expression ex = ce.Base;
                while (ex != null)
                {
                    if (ex is IndexExpr)
                        ex = ((IndexExpr)ex).Index;
                    else if (ex is MemberExpr)
                    {
                        MemberExpr me = ex as MemberExpr;
                        if (me.Indexer == ":")
                        {
                            isMethod = true;
                            break;
                        }
                        else
                            break;
                        //ex = me.Ident;
                    }
                    else
                        break;
                }

                foreach (Expression e2 in ce.Arguments)
                {
                    DoExpr(e2);
                    if (e2 is CallExpr || block.Chunk.Instructions[block.Chunk.Instructions.Count - 1].Opcode == Instruction.LuaOpcode.CALL)
                    {
                        isZero = true;
                        Instruction i_ = block.Chunk.Instructions[block.Chunk.Instructions.Count - 1];
                        Debug.Assert(i_.Opcode == Instruction.LuaOpcode.CALL);
                        i_.C = 0;
                    }
                }

                Instruction i = new Instruction("CALL");
                i.A = breg;
                if (isMethod)
                    //i.B++;
                    i.B = isZero ? 2 : (ce.Arguments.Count > 0 ? 2 + ce.Arguments.Count : 2);
                else
                    i.B = isZero ? 0 : (ce.Arguments.Count > 0 ? 1 + ce.Arguments.Count : 1);

                i.C = setVarLhsCount == 0 || setVarLhsCount == -1 ?
                    1 : //(isZero ? 0 : 1) :
                    1 + setVarLhsCount; // (isZero ? 0 : 1 + setVarLhsCount);
                //i.C = setVarLhsCount == 0 || setVarLhsCount == -1 ? 1 : 1 + setVarLhsCount;
                emit(i);
                return;
            }
            else if (e is StringCallExpr)
            {
                throw new Exception();
            }
            else if (e is TableCallExpr)
            {
                throw new Exception();
            }
            else if (e is IndexExpr)
            {
                IndexExpr ie = e as IndexExpr;
                int regnum = block.regnum;
                DoExpr(ie.Base);
                DoExpr(ie.Index);
                Instruction i = new Instruction("GETTABLE");
                i.A = regnum;
                i.B = regnum;
                i.C = block.regnum - 1;// block.getreg();
                emit(i);
                block.regnum = regnum + 1;
                return;
            }
            else if (e is InlineFunctionExpression) // |<args>| -> <exprs>
            {
                InlineFunctionExpression i = e as InlineFunctionExpression;
                AnonymousFunctionExpr af = new AnonymousFunctionExpr();
                af.Arguments = i.Arguments;
                af.IsVararg = i.IsVararg;
                af.Body = new List<Statement>()
                {
                    new ReturnStatement
                    {
                        Arguments = i.Expressions
                    }
                };
                DoExpr(af);
            }
            else if (e is MemberExpr)
            {
                MemberExpr me = e as MemberExpr;
                if (me.Indexer == ".")
                {
                    int regnum = block.regnum;
                    DoExpr(me.Base);
                    DoExpr(new StringExpr(me.Ident), false, -1, true);
                    Instruction i = new Instruction("GETTABLE");
                    i.A = regnum;
                    i.B = regnum;
                    i.C = 256 + block.K[me.Ident];
                    //i.C = block.regnum - 1;// block.getreg();
                    emit(i);
                    block.regnum = regnum + 1;
                    return;
                }
                else if (me.Indexer == ":")
                {
                    int regnum = block.regnum;
                    DoExpr(me.Base);
                    DoExpr(new StringExpr(me.Ident), false, -1, true);
                    Instruction i = new Instruction("SELF");
                    i.A = regnum;
                    i.B = regnum;
                    i.C = 256 + block.K[me.Ident];
                    //i.C = block.regnum - 1;// block.getreg();
                    emit(i);
                    block.regnum = regnum + 1;
                    return;

                }
                else
                    throw new Exception("Unknown member indexer '" + me.Indexer + "'");
            }
            else if (e is NilExpr)
            {
                Instruction i = new Instruction("LOADNIL");
                i.A = block.getreg();
                i.B = setVarLhsCount == -1 ? i.A : setVarLhsCount - 1;
                i.C = 0;
                emit(i);
                return;
            }
            else if (e is NumberExpr)
            {
                NumberExpr ne = e as NumberExpr;

                // TODO: this can optimized into a Dictionary to avoid re-parsing numbers each time
                double r;
                int x = Lua.luaO_str2d(ne.Value.Replace("_", ""), out r);
                if (x == 0)
                    throw new LuaSourceException(line, 0, "Invalid number");

                if (onlyCheckConsts == false)
                {
                    Instruction i = new Instruction("loadk");
                    i.A = block.getreg();
                    i.Bx = block.K[r];
                    emit(i);
                }
                else
                    block.K.Check(r);
                return;
            }
            else if (e is StringExpr)
            {

                StringExpr se = e as StringExpr;
                string s = se.Value;
                if (se.StringType != TokenType.LongString)
                    s = Unescaper.Unescape(s);
                else
                {
                    int i = 1;
                    while (s[i] != '[')
                        i++;
                    i++;
                    s = s.Substring(i, s.Length - i - 2);
                }

                if (onlyCheckConsts == false)
                {
                    Instruction i2 = new Instruction("loadk");
                    i2.A = block.getreg();
                    i2.Bx = block.K[s];
                    emit(i2);
                }
                else
                    block.K.Check(s);
                return;
            }
            else if (e is TableConstructorExpr)
            {
                Instruction i = new Instruction("NEWTABLE");
                int tblA = block.regnum;
                i.A = block.getreg();
                i.B = 0;
                i.C = 0;
                emit(i);

                TableConstructorExpr tce = e as TableConstructorExpr;
                if (tce.EntryList.Count == 0)
                    return;

                int b = 0;
                bool wasLastCall = false;
                foreach (Expression e2 in tce.EntryList)
                {
                    if (e2 is TableConstructorKeyExpr)
                    {
                        TableConstructorKeyExpr tcke = e2 as TableConstructorKeyExpr;
                        DoExpr(tcke.Key);
                        DoExpr(tcke.Value);
                    }
                    else if (e2 is TableConstructorNamedFunctionExpr)
                    {
                        TableConstructorNamedFunctionExpr tcnfe = e2 as TableConstructorNamedFunctionExpr;
                    }
                    else if (e2 is TableConstructorStringKeyExpr)
                    {
                        TableConstructorStringKeyExpr tcske = e2 as TableConstructorStringKeyExpr;
                        DoExpr(new StringExpr(tcske.Key));
                        DoExpr(tcske.Value);
                    }
                    else if (e2 is TableConstructorValueExpr)
                    {
                        TableConstructorValueExpr tcve = e2 as TableConstructorValueExpr;
                        DoExpr(tcve.Value);
                        if (tcve.Value is VarargExpr || tcve.Value is CallExpr)
                            wasLastCall = true;
                        else
                            wasLastCall = false;
                    }

                    b++;
                }

                i.B = b;

                i = new Instruction("SETLIST");
                i.A = tblA;
                if (wasLastCall)
                    i.B = 0;
                else
                    i.B = block.regnum - 1;
                i.C = tblA + 1;
                emit(i);
                block.regnum = tblA;
                return;
            }
            else if (e is UnOpExpr)
            {
                UnOpExpr uoe = e as UnOpExpr;
                switch (uoe.GetOperator())
                {
                    case UnaryOperator.Not:
                        unOp("NOT", uoe.Rhs);
                        return;
                    case UnaryOperator.Length:
                        unOp("LEN", uoe.Rhs);
                        return;
                    case UnaryOperator.BitNot:
                        CallExpr ce = new CallExpr();
                        ce.Arguments.Add(uoe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } },
                            Ident = "bnot",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case UnaryOperator.Negate:
                        unOp("UNM", uoe.Rhs);
                        return;
                    case UnaryOperator.UnNegate:
                        ce = new CallExpr();
                        ce.Arguments.Add(uoe.Rhs);
                        ce.Base = new MemberExpr()
                        {
                            Base = new VariableExpression() { Var = new Variable() { Name = "math", IsGlobal = true } },
                            Ident = "abs",
                            Indexer = ".",
                        };
                        DoExpr(ce);
                        return;
                    case UnaryOperator.NONE:
                    default:
                        throw new Exception("Unknown unary operator '" + uoe.Op + "'");
                }
            }
            else if (e is VarargExpr)
            {
                if (block.Chunk.Vararg == 0)
                    throw new LuaSourceException(0, 0, "Cannot use varargs (...) outside of a vararg function");
                Instruction i = new Instruction("VARARG");
                i.A = block.getreg();
                if (setVar)
                {
                    i.B = setVarLhsCount == -1 ? 0 : 1 + setVarLhsCount;
                }
                else
                {
                    i.B = 0;
                }
                emit(i);
                return;
            }
            else if (e is VariableExpression)
            {
                VariableExpression ve = e as VariableExpression;
                if (ve.Var.IsGlobal == false)
                { // local
                    if (setVar)
                    {
                        //Instruction i = new Instruction("move");
                        //i.B = block.V[ve.Var.Name]; // moved into here
                        //i.A = block.getreg(); // from here
                        //emit(i);

                        int _TMP_001_ = block.V[ve.Var.Name]; // Should probably just add a Check method in Var2Reg
                        block.CheckLocalName(ve.Var.Name);
                    }
                    else
                    {
                        Instruction i = new Instruction("move");
                        i.B = block.V[ve.Var.Name]; // moved into here
                        i.A = block.getreg(); // from here
                        emit(i);
                    }
                }
                else
                { // global
                    Instruction i = null;
                    if (setVar)
                    {
                        i = new Instruction("setglobal");
                        i.A = block.regnum - 1; // ret
                    }
                    else
                    {
                        i = new Instruction("getglobal");
                        i.A = block.getreg(); // ret
                    }

                    i.Bx = block.K[ve.Var.Name]; // const
                    emit(i);
                }
                return;
            }

            throw new NotImplementedException(e.GetType().Name + " is not implemented");
        }
Exemple #3
0
        Expression ParseSuffixedExpr(Scope scope, bool onlyDotColon = false)
        {
            // base primary expression
            Expression prim = ParsePrimaryExpr(scope);

            while (true)
            {
                if (reader.IsSymbol('.') || reader.IsSymbol(':'))
                {
                    string symb = reader.Get().Data; // '.' or ':'
                    // TODO: should we allow keywords? I vote no.
                    if (!reader.Is(TokenType.Ident))
                        error("<Ident> expected");

                    Token id = reader.Get();
                    MemberExpr m = new MemberExpr();
                    m.Base = prim;
                    m.Indexer = symb;
                    m.Ident = id.Data;

                    prim = m;
                }
                else if (!onlyDotColon && reader.ConsumeSymbol('['))
                {
                    int pass = 0;
                    const int maxamount = 100;
                    bool wasLastNumeric = false;
                    bool first = true;
                    bool hadComma = false;
                    do
                    {
                        Token tok = reader.Peek();
                        int col = tok.Column;
                        int line = tok.Line;

                        Expression ex = ParseExpr(scope);
                        //if (!reader.ConsumeSymbol(']'))
                        //error("']' expected");

                        IndexExpr i = new IndexExpr();
                        i.Base = prim;
                        i.Index = ex;

                        prim = i;

                        if ((first || wasLastNumeric) && ex is NumberExpr && hadComma == false)
                        {
                            tok = reader.Peek();
                            bool cma = reader.ConsumeSymbol(',');
                            if (cma && hadComma == false && first == false)
                                error("Unexpected ',' in matrice indexing", tok.Line, tok.Column, tok);
                            //else if (cma == false && hadComma)
                            //    ;
                            hadComma = cma;
                        }
                        else
                        {
                            tok = reader.Peek();
                            bool cma = reader.ConsumeSymbol(',');
                            //if (cma == false)
                            //    break;
                            if (cma && hadComma == false)
                                error("Unexpected ',' in matrice indexing", -1, -1, tok);
                            else if (cma == false && ex is NumberExpr == false && wasLastNumeric && hadComma == false)
                            {
                                error("Expected numeric constant in matrice indexing", line, col, tok);
                            }
                            else if (cma == false && hadComma)
                                if (tok.Type == TokenType.Symbol && tok.Data == "]")
                                    ;
                                else
                                    error("Expected ','", -1, -1, tok);
                            else if (cma == false)
                            {
                                break;
                            }
                            else
                            {
                                hadComma = true;
                            }
                            hadComma = cma;
                        }

                        if (pass++ >= maxamount)
                            error("Maximum index depth reached");

                        wasLastNumeric = ex is NumberExpr;
                        first = false;
                    } while (!(reader.Peek().Data == "]"));
                    if (!reader.ConsumeSymbol(']'))
                        error("']' expected");
                }
                else if (!onlyDotColon && reader.ConsumeSymbol('('))
                {
                    List<Expression> args = new List<Expression>();
                    while (!reader.ConsumeSymbol(')'))
                    {
                        Expression ex = ParseExpr(scope);

                        args.Add(ex);
                        if (!reader.ConsumeSymbol(','))
                        {
                            if (reader.ConsumeSymbol(')'))
                                break;
                            else
                                error("')' expected");
                            break;
                        }
                    }
                    CallExpr c = new CallExpr();
                    c.Base = prim;
                    c.Arguments = args;

                    prim = c;
                }
                else if (!onlyDotColon &&
                        (reader.Is(TokenType.SingleQuoteString) ||
                        reader.Is(TokenType.DoubleQuoteString) ||
                        reader.Is(TokenType.LongString)))
                {
                    //string call

                    StringCallExpr e = new StringCallExpr();
                    e.Base = prim;
                    e.Arguments = new List<Expression> { new StringExpr(reader.Peek().Data) { StringType = reader.Peek().Type } };
                    reader.Get();
                    prim = e;
                }
                else if (!onlyDotColon && reader.IsSymbol('{'))
                {
                    // table call

                    // Fix for the issue with whole expr being parsed, not just table.
                    // See LuaMinify issue #2 (https://github.com/stravant/LuaMinify/issues/2)
                    //Expression ex = ParseExpr(scope);
                    Expression ex = ParseSimpleExpr(scope);

                    TableCallExpr t = new TableCallExpr();
                    t.Base = prim;
                    t.Arguments = new List<Expression> { ex };

                    prim = t;
                }
                else
                    break;
            }
            return prim;
        }