public static InlineFunctionExpression InlineFunction(AnonymousFunctionExpr e) { if (!CanInline(e)) { throw new Exception("Cannot inline function!"); } ReturnStatement rs = e.Body[0] as ReturnStatement; InlineFunctionExpression ife = new InlineFunctionExpression(); foreach (Variable v in e.Arguments) { ife.Arguments.Add(v); } ife.IsVararg = e.IsVararg; foreach (Expression expr in rs.Arguments) { ife.Expressions.Add(expr); } ife.Scope = e.Scope; rs.Scope = e.Scope; return(ife); }
static List <CompletionItem> DoExpr(Expression e) { List <CompletionItem> ret = new List <CompletionItem>(); if (e is AnonymousFunctionExpr) { AnonymousFunctionExpr f = e as AnonymousFunctionExpr; for (int i = 0; i < f.Arguments.Count; i++) { ret.Add(new CompletionItem(f.Arguments[i].Name)); } ret.AddRange(DoChunk(f.Body)); } else if (e is BinOpExpr) { } else if (e is BoolExpr) { } else if (e is CallExpr && (!(e is StringCallExpr) && !(e is TableCallExpr))) { } else if (e is StringCallExpr) { ret.AddRange(DoExpr(((StringCallExpr)e).Base)); } else if (e is TableCallExpr) { ret.AddRange(DoExpr(((StringCallExpr)e).Base)); } else if (e is IndexExpr) { ret.AddRange(DoExpr(((IndexExpr)e).Base)); ret.AddRange(DoExpr(((IndexExpr)e).Index)); } else if (e is InlineFunctionExpression) // |<args>| -> <exprs> { InlineFunctionExpression ife = e as InlineFunctionExpression; for (int i = 0; i < ife.Arguments.Count; i++) { ret.Add(new CompletionItem(ife.Arguments[i].Name)); } } else if (e is TableConstructorKeyExpr) { TableConstructorKeyExpr t = e as TableConstructorKeyExpr; ret.AddRange(DoExpr(t.Key)); ret.AddRange(DoExpr(t.Value)); } else if (e is MemberExpr) { MemberExpr m = e as MemberExpr; ret.AddRange(DoExpr(m.Base)); ret.Add(new CompletionItem(m.Ident)); } else if (e is NilExpr) { } else if (e is NumberExpr) { } else if (e is StringExpr) { StringExpr se = e as StringExpr; } else if (e is TableConstructorStringKeyExpr) { TableConstructorStringKeyExpr tcske = e as TableConstructorStringKeyExpr; ret.Add(new CompletionItem(tcske.Key)); ret.AddRange(DoExpr(tcske.Value)); } else if (e is TableConstructorExpr) { TableConstructorExpr t = e as TableConstructorExpr; for (int i = 0; i < t.EntryList.Count; i++) { ret.AddRange(DoExpr(t.EntryList[i])); } } else if (e is UnOpExpr) { } else if (e is TableConstructorValueExpr) { ret.AddRange(DoExpr((e as TableConstructorValueExpr).Value)); } else if (e is VarargExpr) { } else if (e is VariableExpression) { ret.Add(new CompletionItem((e as VariableExpression).Var.Name)); } return(ret); }
internal string DoExpr(Expression e) { string ret = null; if (e is AnonymousFunctionExpr) // function() ... end { // TODO: optimize into InlineFunctionExpr? AnonymousFunctionExpr f = e as AnonymousFunctionExpr; StringBuilder sb = new StringBuilder(); sb.Append("function("); for (int i = 0; i < f.Arguments.Count; i++) { sb.Append(f.Arguments[i].Name); if (i != f.Arguments.Count - 1 || f.IsVararg) { sb.Append(","); } } if (f.IsVararg) { sb.Append("..."); } sb.Append(")"); sb.Append(DoChunk(f.Body)); sb.Append(" end"); ret = sb.ToString(); } else if (e is BinOpExpr) { string left = DoExpr((e as BinOpExpr).Lhs); string op = (e as BinOpExpr).Op; string right = DoExpr((e as BinOpExpr).Rhs); ret = string.Format("{0}{1}{2}", left, op, right); } else if (e is BoolExpr) { bool val = (e as BoolExpr).Value; ret = val ? "true" : "false"; } else if (e is CallExpr && (!(e is StringCallExpr) && !(e is TableCallExpr))) { CallExpr c = e as CallExpr; StringBuilder sb = new StringBuilder(); sb.Append(DoExpr(c.Base) + "("); for (int i = 0; i < c.Arguments.Count; i++) { sb.Append(DoExpr(c.Arguments[i])); if (i != c.Arguments.Count - 1) { sb.Append(","); } } sb.Append(")"); ret = sb.ToString(); } else if (e is StringCallExpr) { StringCallExpr s = e as StringCallExpr; ret = string.Format("{0}{1}", DoExpr(s.Base), DoExpr(s.Arguments[0])); } else if (e is TableCallExpr) { TableCallExpr s = e as TableCallExpr; ret = string.Format("{0}{1}", DoExpr(s.Base), DoExpr(s.Arguments[0])); } else if (e is IndexExpr) { IndexExpr i = e as IndexExpr; ret = string.Format("{0}[{1}]", DoExpr(i.Base), DoExpr(i.Index)); } else if (e is InlineFunctionExpression) // |<args>| -> <exprs> { InlineFunctionExpression ife = e as InlineFunctionExpression; StringBuilder sb = new StringBuilder(); sb.Append("|"); for (int i = 0; i < ife.Arguments.Count; i++) { sb.Append(ife.Arguments[i].Name); if (i != ife.Arguments.Count - 1 || ife.IsVararg) { sb.Append(", "); } } if (ife.IsVararg) { sb.Append("..."); } sb.Append("|->"); for (int i2 = 0; i2 < ife.Expressions.Count; i2++) { sb.Append(DoExpr(ife.Expressions[i2])); if (i2 != ife.Expressions.Count - 1) { sb.Append(","); } } ret = sb.ToString(); } else if (e is TableConstructorKeyExpr) { TableConstructorKeyExpr t = e as TableConstructorKeyExpr; ret = "[" + DoExpr(t.Key) + "]=" + DoExpr(t.Value); } else if (e is MemberExpr) { MemberExpr m = e as MemberExpr; ret = DoExpr(m.Base) + m.Indexer + m.Ident; } else if (e is NilExpr) { ret = "nil"; } else if (e is NumberExpr) { ret = (e as NumberExpr).Value; } else if (e is StringExpr) { StringExpr se = e as StringExpr; string delim = se.StringType == TokenType.SingleQuoteString ? "'" : (se.StringType == TokenType.DoubleQuoteString ? "\"" : "["); if (delim == "[") { // Long strings keep their [=*[ ret = se.Value; } else { ret = delim + se.Value + delim; } } else if (e is TableConstructorStringKeyExpr) { TableConstructorStringKeyExpr tcske = e as TableConstructorStringKeyExpr; ret = tcske.Key + "=" + DoExpr(tcske.Value); } else if (e is TableConstructorExpr) { TableConstructorExpr t = e as TableConstructorExpr; StringBuilder sb = new StringBuilder(); sb.Append("{"); for (int i = 0; i < t.EntryList.Count; i++) { sb.Append(DoExpr(t.EntryList[i])); if (i != t.EntryList.Count - 1) { sb.Append(","); } } sb.Append("}"); ret = sb.ToString(); } else if (e is UnOpExpr) { string op = (e as UnOpExpr).Op; string s = op; if (s.Length != 1) { s += " "; } ret = s + DoExpr((e as UnOpExpr).Rhs); } else if (e is TableConstructorValueExpr) { ret = DoExpr((e as TableConstructorValueExpr).Value); } else if (e is VarargExpr) { ret = "..."; } else if (e is VariableExpression) { ret = (e as VariableExpression).Var.Name; } if (ret != null) { return(string.Format("{0}{1}{2}", "(".Repeat(e.ParenCount), ret, ")".Repeat(e.ParenCount))); } throw new NotImplementedException(e.GetType().Name + " is not implemented"); }
internal string DoExpr(Expression e, List <Token> tok, ref int index, Scope s) { int startP = index; for (int i = 0; i < e.ParenCount; i++) { index++; } string ret = null; if (e is AnonymousFunctionExpr) // function() ... end { AnonymousFunctionExpr f = e as AnonymousFunctionExpr; StringBuilder sb = new StringBuilder(); sb.Append(fromToken(tok[index++], s)); // 'function' sb.Append(fromToken(tok[index++], s)); // '(' for (int i2 = 0; i2 < f.Arguments.Count; i2++) { sb.Append(fromToken(tok[index++], s)); if (i2 != f.Arguments.Count - 1 || f.IsVararg) { sb.Append(fromToken(tok[index++], s) + " "); } } if (f.IsVararg) { sb.Append(fromToken(tok[index++], s)); } sb.Append(fromToken(tok[index++], s)); // ')' if (f.Body.Count > 1) { sb.Append(options.EOL); indent++; sb.Append(DoChunk(f.Body)); sb.Append(nldedent()); } else if (f.Body.Count == 0) { sb.Append(" "); } else { sb.Append(" " + DoStatement(f.Body[0])); sb.Append(" "); } //sb.Append(DoChunk(f.Body)); // Ugh. sb.Append(fromToken(tok[index++], s)); // <end> ret = sb.ToString(); } else if (e is BinOpExpr) { //int i = 0; string left = DoExpr((e as BinOpExpr).Lhs, tok, ref index, s); string op = fromToken(tok[index++], s); string right = DoExpr((e as BinOpExpr).Rhs, tok, ref index, s); ret = string.Format("{0} {1} {2}", left, op, right); } else if (e is BoolExpr) { ret = fromToken(tok[index++], s); } else if (e is CallExpr && (!(e is StringCallExpr) && !(e is TableCallExpr))) { CallExpr c = e as CallExpr; StringBuilder sb = new StringBuilder(); sb.Append(DoExpr(c.Base, tok, ref index, s) // <base> + fromToken(tok[index++], s)); // '(' for (int i = 0; i < c.Arguments.Count; i++) { sb.Append(DoExpr(c.Arguments[i], tok, ref index, s)); if (i != c.Arguments.Count - 1) { sb.Append(fromToken(tok[index++], s)); // ', ' sb.Append(" "); } } sb.Append(fromToken(tok[index++], s)); // ')' ret = sb.ToString(); } else if (e is StringCallExpr) { StringCallExpr sc = e as StringCallExpr; ret = string.Format("{0} {1}", DoExpr(sc.Base, tok, ref index, s), DoExpr(sc.Arguments[0], tok, ref index, s)); } else if (e is TableCallExpr) { TableCallExpr sc = e as TableCallExpr; ret = string.Format("{0} {1}", DoExpr(sc.Base, tok, ref index, s), DoExpr(sc.Arguments[0], tok, ref index, s)); } else if (e is IndexExpr) { IndexExpr i = e as IndexExpr; ret = string.Format("{0}{1}{2}{3}", DoExpr(i.Base, tok, ref index, s), fromToken(tok[index++], s), DoExpr(i.Index, tok, ref index, s), fromToken(tok[index++], s)); } else if (e is InlineFunctionExpression) // |<args>| -> <exprs> { InlineFunctionExpression ife = e as InlineFunctionExpression; StringBuilder sb = new StringBuilder(); sb.Append(fromToken(tok[index++], s)); // '|; for (int i = 0; i < ife.Arguments.Count; i++) { sb.Append(fromToken(tok[index++], s)); // <arg name> if (i != ife.Arguments.Count - 1 || ife.IsVararg) { sb.Append(fromToken(tok[index++], s)); // ',' sb.Append(" "); } } if (ife.IsVararg) { sb.Append(fromToken(tok[index++], s)); // '...' sb.Append(" "); } sb.Append(fromToken(tok[index++], s)); // '|' sb.Append(" "); sb.Append(fromToken(tok[index++], s)); // '->' sb.Append(" "); for (int i2 = 0; i2 < ife.Expressions.Count; i2++) { sb.Append(DoExpr(ife.Expressions[i2], tok, ref index, s)); if (i2 != ife.Expressions.Count - 1) { sb.Append(fromToken(tok[index++], s)); // ',' sb.Append(" "); } } ret = sb.ToString(); } else if (e is TableConstructorKeyExpr) { TableConstructorKeyExpr t = e as TableConstructorKeyExpr; ret = fromToken(tok[index++], s) + DoExpr(t.Key, tok, ref index, s) + fromToken(tok[index++], s) + " " + fromToken(tok[index++], s) + " " + DoExpr(t.Value, tok, ref index, s); } else if (e is MemberExpr) { MemberExpr m = e as MemberExpr; ret = DoExpr(m.Base, tok, ref index, s) + fromToken(tok[index++], s) + fromToken(tok[index++], s); } else if (e is NilExpr) { ret = fromToken(tok[index++], s); } else if (e is NumberExpr) { ret = fromToken(tok[index++], s); } else if (e is StringExpr) { ret = fromToken(tok[index++], s); } else if (e is TableConstructorStringKeyExpr) { TableConstructorStringKeyExpr tcske = e as TableConstructorStringKeyExpr; ret = fromToken(tok[index++], s); // key ret += " "; ret += fromToken(tok[index++], s); // '=' ret += " "; ret += DoExpr(tcske.Value, tok, ref index, s); // value } else if (e is TableConstructorExpr) { TableConstructorExpr t = e as TableConstructorExpr; StringBuilder sb = new StringBuilder(); sb.Append(fromToken(tok[index++], s)); // '{' sb.Append(" "); for (int i = 0; i < t.EntryList.Count; i++) { sb.Append(DoExpr(t.EntryList[i], tok, ref index, s)); if (i != t.EntryList.Count - 1) { sb.Append(fromToken(tok[index++], s)); // ',' sb.Append(" "); } } if (t.EntryList.Count > 0) // empty table constructor is just { } { sb.Append(" "); } sb.Append(fromToken(tok[index++], s)); // '}' ret = sb.ToString(); } else if (e is UnOpExpr) { UnOpExpr u = e as UnOpExpr; string sc = fromToken(tok[index++], s); if (u.Op.Length != 1) { sc += " "; } ret = sc + DoExpr(u.Rhs, tok, ref index, s); } else if (e is TableConstructorValueExpr) { ret = DoExpr(((TableConstructorValueExpr)e).Value, tok, ref index, s); } else if (e is VarargExpr) { ret = fromToken(tok[index++], s); } else if (e is VariableExpression) { ret = fromToken(tok[index++], s); } else if (e is TableConstructorNamedFunctionExpr) { ret = DoStatement(((TableConstructorNamedFunctionExpr)e).Value); } if (ret != null) { if (e.ParenCount > 0) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < e.ParenCount; i++) { sb.Append(fromToken(tok[startP++], s)); } sb.Append(ret); for (int i = 0; i < e.ParenCount; i++) { sb.Append(fromToken(tok[index++], s)); } return(sb.ToString()); } else { return(ret); } } //return string.Format("{0}{1}{2}", "(".Repeat(e.ParenCount), ret, ")".Repeat(e.ParenCount)); throw new NotImplementedException(e.GetType().Name + " is not implemented"); }
string DoExpr(Expression e) { string ret = ""; if (e is AnonymousFunctionExpr) // function() ... end { AnonymousFunctionExpr f = e as AnonymousFunctionExpr; StringBuilder sb = new StringBuilder(); sb.Append("function("); for (int i = 0; i < f.Arguments.Count; i++) { sb.Append(f.Arguments[i].Name); if (i != f.Arguments.Count - 1 || f.IsVararg) { sb.Append(", "); } } if (f.IsVararg) { sb.Append("..."); } sb.Append(")"); if (f.Body.Count > 1) { sb.Append(EOL); indent++; sb.Append(DoChunk(f.Body)); sb.Append(nldedent()); sb.Append("end"); } else if (f.Body.Count == 0) { sb.Append(" end"); } else { sb.Append(" " + DoStatement(f.Body[0])); sb.Append(" end"); } ret = sb.ToString(); } else if (e is BinOpExpr) { BinOpExpr b = e as BinOpExpr; string left = DoExpr(b.Lhs); string op = b.Op; string right = DoExpr(b.Rhs); if (op == "!=") { op = "~="; } if (op == ">>") { ret = string.Format("bit.rshift({0}, {1})", left, right); } else if (op == "<<") { ret = string.Format("bit.lshift({0}, {1})", left, right); } else if (op == "&") { ret = string.Format("bit.band({0}, {1})", left, right); } else if (op == "|") { ret = string.Format("bit.bor({0}, {1})", left, right); } else if (op == "^^") { ret = string.Format("bit.bxor({0}, {1})", left, right); } else { ret = string.Format("{0} {1} {2}", left, op, right); } } else if (e is BoolExpr) { bool val = (e as BoolExpr).Value; ret = val ? "true" : "false"; } else if (e is CallExpr && (!(e is StringCallExpr) && !(e is TableCallExpr))) { CallExpr c = e as CallExpr; StringBuilder sb = new StringBuilder(); sb.Append(DoExpr(c.Base) + "("); for (int i = 0; i < c.Arguments.Count; i++) { sb.Append(DoExpr(c.Arguments[i])); if (i != c.Arguments.Count - 1) { sb.Append(", "); } } sb.Append(")"); ret = sb.ToString(); } else if (e is StringCallExpr) { StringCallExpr s = e as StringCallExpr; ret = string.Format("{0} {1}", DoExpr(s.Base), DoExpr(s.Arguments[0])); } else if (e is TableCallExpr) { TableCallExpr s = e as TableCallExpr; ret = string.Format("{0} {1}", DoExpr(s.Base), DoExpr(s.Arguments[0])); } else if (e is IndexExpr) { IndexExpr i = e as IndexExpr; ret = string.Format("{0}[{1}]", DoExpr(i.Base), DoExpr(i.Index)); } else if (e is InlineFunctionExpression) // |<args>| -> <exprs> { InlineFunctionExpression ife = e as InlineFunctionExpression; StringBuilder sb = new StringBuilder(); sb.Append("function("); for (int i = 0; i < ife.Arguments.Count; i++) { sb.Append(ife.Arguments[i].Name); if (i != ife.Arguments.Count - 1 || ife.IsVararg) { sb.Append(", "); } } if (ife.IsVararg) { sb.Append("..."); } sb.Append(") return "); for (int i2 = 0; i2 < ife.Expressions.Count; i2++) { sb.Append(DoExpr(ife.Expressions[i2])); if (i2 != ife.Expressions.Count - 1) { sb.Append(", "); } } sb.Append(" end"); ret = sb.ToString(); } else if (e is TableConstructorKeyExpr) { TableConstructorKeyExpr t = e as TableConstructorKeyExpr; ret = "[" + DoExpr(t.Key) + "] = " + DoExpr(t.Value); } else if (e is MemberExpr) { MemberExpr m = e as MemberExpr; ret = DoExpr(m.Base) + m.Indexer + m.Ident; } else if (e is NilExpr) { ret = "nil"; } else if (e is NumberExpr) { ret = (e as NumberExpr).Value; ret = ret.Replace("_", ""); } else if (e is StringExpr) { StringExpr se = e as StringExpr; string delim = se.StringType == TokenType.SingleQuoteString ? "'" : se.StringType == TokenType.DoubleQuoteString ? "\"" : "["; if (delim == "[") { // Long strings keep their [=*[ ret = se.Value; } else { ret = delim + se.Value + delim; } } else if (e is TableConstructorStringKeyExpr) { TableConstructorStringKeyExpr tcske = e as TableConstructorStringKeyExpr; ret = tcske.Key + " = " + DoExpr(tcske.Value); } else if (e is TableConstructorExpr) { TableConstructorExpr t = e as TableConstructorExpr; StringBuilder sb = new StringBuilder(); sb.Append("{ "); for (int i = 0; i < t.EntryList.Count; i++) { sb.Append(DoExpr(t.EntryList[i])); if (i != t.EntryList.Count - 1) { sb.Append(", "); } } sb.Append("} "); ret = sb.ToString(); } else if (e is UnOpExpr) { string op = (e as UnOpExpr).Op; if (op == "!") { op = "not"; } string s = op; if (s == "~") { ret = "bit.bnot(" + DoExpr((e as UnOpExpr).Rhs) + ")"; } else if (s == "+") { ret = "math.abs(" + DoExpr((e as UnOpExpr).Rhs) + ")"; } else { if (s.Length != 1) { s += " "; } ret = s + DoExpr((e as UnOpExpr).Rhs); } } else if (e is TableConstructorValueExpr) { ret = DoExpr((e as TableConstructorValueExpr).Value); } else if (e is VarargExpr) { ret = "..."; } else if (e is VariableExpression) { ret = (e as VariableExpression).Var.Name; } else if (e is TableConstructorNamedFunctionExpr) { TableConstructorNamedFunctionExpr fs = e as TableConstructorNamedFunctionExpr; AnonymousFunctionExpr a = new AnonymousFunctionExpr(); a.Arguments = fs.Value.Arguments; a.Arguments.Insert(0, new Variable() { Name = "self", IsGlobal = false, References = -1 }); a.Body = fs.Value.Body; a.IsVararg = fs.Value.IsVararg; ret = DoExpr(fs.Value.Name) + " = " + DoExpr(a); } return(string.Format("{0}{1}{2}", oparens(e.ParenCount), ret, cparens(e.ParenCount))); throw new NotImplementedException(e.GetType().Name + " is not implemented"); }
Expression ParseSimpleExpr(Scope scope) { if (reader.Is(TokenType.Number)) { return new NumberExpr { Value = reader.Get().Data } } ; else if (reader.Is(TokenType.DoubleQuoteString) || reader.Is(TokenType.SingleQuoteString) || reader.Is(TokenType.LongString)) { StringExpr s = new StringExpr { Value = reader.Peek().Data, StringType = reader.Peek().Type }; reader.Get(); return(s); } else if (reader.ConsumeKeyword("nil")) { return(new NilExpr()); } else if (reader.IsKeyword("false") || reader.IsKeyword("true")) { return new BoolExpr { Value = reader.Get().Data == "true" } } ; else if (reader.ConsumeSymbol("...")) { return(new VarargExpr()); } else if (reader.ConsumeSymbol('{')) { TableConstructorExpr v = new TableConstructorExpr(); while (true) { if (reader.IsSymbol('[')) { // key reader.Get(); // eat '[' Expression key = ParseExpr(scope); if (!reader.ConsumeSymbol(']')) { error("']' expected"); break; } if (!reader.ConsumeSymbol('=')) { error("'=' Expected"); break; } Expression value = ParseExpr(scope); v.EntryList.Add(new TableConstructorKeyExpr { Key = key, Value = value, }); } else if (reader.Is(TokenType.Ident)) { // value or key Token lookahead = reader.Peek(1); if (lookahead.Type == TokenType.Symbol && lookahead.Data == "=") { // we are a key Token key = reader.Get(); if (!reader.ConsumeSymbol('=')) { error("'=' Expected"); } Expression value = ParseExpr(scope); v.EntryList.Add(new TableConstructorStringKeyExpr { Key = key.Data, Value = value, }); } else { // we are a value Expression val = ParseExpr(scope); v.EntryList.Add(new TableConstructorValueExpr { Value = val }); } } #if !VANILLA_LUA else if (reader.ConsumeKeyword("function")) { if (reader.Peek().Type != TokenType.Ident) { error("function name expected"); } string name = reader.Get().Data; FunctionStatement fs = ParseFunctionArgsAndBody(scope); fs.IsLocal = false; fs.Name = new StringExpr(name); v.EntryList.Add(new TableConstructorNamedFunctionExpr { Value = fs }); } #endif else if (reader.ConsumeSymbol('}')) { break; } else { //value Expression value = ParseExpr(scope); v.EntryList.Add(new TableConstructorValueExpr { Value = value }); } if (reader.ConsumeSymbol(';') || reader.ConsumeSymbol(',')) { // I could have used just an empty statement (';') here, instead of { } // but that leaves a warning, which clutters up the output // other than that, all is good } else if (reader.ConsumeSymbol('}')) { break; } else { error("'}' or table entry Expected"); break; } } return(v); } else if (reader.ConsumeKeyword("function")) { AnonymousFunctionExpr func = ParseExprFunctionArgsAndBody(scope); //func.IsLocal = true; return(func); } #if !VANILLA_LUA else if (reader.ConsumeSymbol('|')) { // inline function... |<arg list>| -> <expr>, <expr> InlineFunctionExpression func = new InlineFunctionExpression(); func.Scope = new Scope(scope); // arg list List <Variable> arglist = new List <Variable>(); bool isVarArg = false; while (reader.ConsumeSymbol('|') == false) { if (reader.Is(TokenType.Ident)) { Variable arg = new Variable(); arg.Name = reader.Get().Data; func.Scope.AddLocal(arg); arglist.Add(arg); if (!reader.ConsumeSymbol(',')) { if (reader.ConsumeSymbol('|')) { break; } else { error("'|' expected"); break; } } } else if (reader.ConsumeSymbol("...")) { isVarArg = true; if (!reader.ConsumeSymbol('|')) { error("'...' must be the last argument of a function"); } break; } else { error("Argument name or '...' expected"); break; } } if (!reader.ConsumeSymbol("->")) { error("'->' expected"); } // body List <Expression> body = new List <Expression> { ParseExpr(func.Scope) }; while (reader.ConsumeSymbol(',')) { body.Add(ParseExpr(func.Scope)); } // end //nodeFunc.AstType = AstType.Function; func.Arguments = arglist; func.Expressions = body; func.IsVararg = isVarArg; return(func); } #endif else { return(ParseSuffixedExpr(scope)); } }
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"); }