├── .gitignore ├── IronLua.sln ├── IronLua ├── Compiler │ ├── Ast │ │ ├── Arguments.cs │ │ ├── AstExtensions.cs │ │ ├── BinaryOp.cs │ │ ├── Block.cs │ │ ├── Elseif.cs │ │ ├── Expression.cs │ │ ├── Field.cs │ │ ├── FunctionBody.cs │ │ ├── FunctionCall.cs │ │ ├── FunctionName.cs │ │ ├── IVisitor.cs │ │ ├── LastStatement.cs │ │ ├── Node.cs │ │ ├── PrefixExpression.cs │ │ ├── Statement.cs │ │ ├── UnaryOp.cs │ │ └── Variable.cs │ ├── ExprHelpers.cs │ ├── FieldVisit.cs │ ├── Generator.cs │ ├── Parser │ │ ├── Input.cs │ │ ├── Lexer.cs │ │ ├── Parser.cs │ │ ├── Symbol.cs │ │ └── Token.cs │ ├── Scope.cs │ └── VariableVisit.cs ├── Constant.cs ├── ExceptionMessage.cs ├── IronLua.csproj ├── Library │ ├── BaseLibrary.cs │ ├── Library.cs │ ├── NumberUtil.cs │ ├── StringFormatter.cs │ └── StringLibrary.cs ├── LuaException.cs ├── LuaRuntimeException.cs ├── LuaSyntaxException.cs ├── MemberInfos.cs ├── Properties │ └── AssemblyInfo.cs ├── Runtime │ ├── Binder │ │ ├── LuaBinaryOperationBinder.cs │ │ ├── LuaConvertBinder.cs │ │ ├── LuaGetIndexBinder.cs │ │ ├── LuaGetMemberBinder.cs │ │ ├── LuaInvokeBinder.cs │ │ ├── LuaInvokeMemberBinder.cs │ │ ├── LuaSetIndexBinder.cs │ │ ├── LuaSetMemberBinder.cs │ │ └── LuaUnaryOperationBinder.cs │ ├── Context.cs │ ├── DynamicCache.cs │ ├── LuaOps.cs │ ├── LuaTable.cs │ ├── MetamethodFallbacks.cs │ ├── RuntimeHelpers.cs │ └── Varargs.cs └── Util │ ├── CharExtensions.cs │ ├── EnumerableExtensions.cs │ ├── HashHelpers.cs │ ├── ParameterInfoExtensions.cs │ └── TypeExtensions.cs ├── README.md ├── Sample ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Sample.csproj └── packages.config └── packages ├── Mono.Linq.Expressions.1.1.0.0 ├── Mono.Linq.Expressions.1.1.0.0.nupkg └── lib │ └── Mono.Linq.Expressions.dll └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | bin/ 3 | obj/ 4 | *ReSharper* 5 | -------------------------------------------------------------------------------- /IronLua.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronLua", "IronLua\IronLua.csproj", "{F166178F-729B-4DB5-8D7C-13C269FB5039}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x86 = Debug|x86 12 | Release|Any CPU = Release|Any CPU 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Debug|x86.ActiveCfg = Debug|Any CPU 19 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Debug|x86.Build.0 = Debug|Any CPU 20 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Release|x86.ActiveCfg = Release|Any CPU 23 | {F166178F-729B-4DB5-8D7C-13C269FB5039}.Release|x86.Build.0 = Release|Any CPU 24 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Debug|x86.ActiveCfg = Debug|x86 27 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Debug|x86.Build.0 = Debug|x86 28 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Release|x86.ActiveCfg = Release|x86 31 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC}.Release|x86.Build.0 = Release|x86 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Arguments.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | abstract class Arguments : Node 6 | { 7 | public abstract T Visit(IArgumentsVisitor visitor); 8 | 9 | public class Normal : Arguments 10 | { 11 | public List Arguments { get; set; } 12 | 13 | public Normal(List arguments) 14 | { 15 | Arguments = arguments; 16 | } 17 | 18 | public override T Visit(IArgumentsVisitor visitor) 19 | { 20 | return visitor.Visit(this); 21 | } 22 | } 23 | 24 | public class Table : Arguments 25 | { 26 | public Expression.Table Value { get; set; } 27 | 28 | public Table(Expression.Table value) 29 | { 30 | Value = value; 31 | } 32 | 33 | public override T Visit(IArgumentsVisitor visitor) 34 | { 35 | return visitor.Visit(this); 36 | } 37 | } 38 | 39 | public class String : Arguments 40 | { 41 | public Expression.String Literal { get; set; } 42 | 43 | public String(Expression.String literal) 44 | { 45 | Literal = literal; 46 | } 47 | 48 | public override T Visit(IArgumentsVisitor visitor) 49 | { 50 | return visitor.Visit(this); 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/AstExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | static class AstExtensions 4 | { 5 | public static Variable LiftVariable(this PrefixExpression prefixExpression) 6 | { 7 | var varPrefixExpr = prefixExpression as PrefixExpression.Variable; 8 | return varPrefixExpr != null ? varPrefixExpr.Var : null; 9 | } 10 | 11 | public static FunctionCall LiftFunctionCall(this PrefixExpression prefixExpression) 12 | { 13 | var funcCallPrefixExpr = prefixExpression as PrefixExpression.FunctionCall; 14 | return funcCallPrefixExpr != null ? funcCallPrefixExpr.Call : null; 15 | } 16 | 17 | public static string LiftIdentifier(this Expression expression) 18 | { 19 | var prefixExpression = expression as Expression.Prefix; 20 | if (prefixExpression == null) 21 | return null; 22 | 23 | var variablePrefixExpr = prefixExpression.Expression as PrefixExpression.Variable; 24 | if (variablePrefixExpr == null) 25 | return null; 26 | 27 | var identifierVariable = variablePrefixExpr.Var as Variable.Identifier; 28 | return identifierVariable != null ? identifierVariable.Value : null; 29 | } 30 | 31 | public static bool IsVarargs(this Expression expression) 32 | { 33 | if (expression is Expression.Varargs) 34 | return true; 35 | 36 | return false; 37 | } 38 | 39 | public static bool IsFunctionCall(this Expression expression) 40 | { 41 | Expression.Prefix exprPrefix; 42 | PrefixExpression.Expression prefixExpr; 43 | 44 | if ((exprPrefix = expression as Expression.Prefix) == null) 45 | return false; 46 | if (exprPrefix.Expression is PrefixExpression.FunctionCall) 47 | return true; 48 | 49 | if ((prefixExpr = exprPrefix.Expression as PrefixExpression.Expression) == null) 50 | return false; 51 | return IsFunctionCall(prefixExpr.Expr); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/BinaryOp.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | enum BinaryOp 4 | { 5 | Or, 6 | And, 7 | Equal, 8 | NotEqual, 9 | Less, 10 | Greater, 11 | LessEqual, 12 | GreaterEqual, 13 | Concat, 14 | Add, 15 | Subtract, 16 | Multiply, 17 | Divide, 18 | Mod, 19 | Power 20 | } 21 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Block.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | class Block : Node 6 | { 7 | public List Statements { get; set; } 8 | public LastStatement LastStatement { get; set; } 9 | 10 | public Block(List statements, LastStatement lastStatement) 11 | { 12 | Statements = statements; 13 | LastStatement = lastStatement; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Elseif.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | class Elseif : Node 4 | { 5 | public Expression Test { get; set; } 6 | public Block Body { get; set; } 7 | 8 | public Elseif(Expression test, Block body) 9 | { 10 | Test = test; 11 | Body = body; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Expression.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | abstract class Expression : Node 6 | { 7 | public abstract T Visit(IExpressionVisitor visitor); 8 | 9 | public class Nil : Expression 10 | { 11 | public override T Visit(IExpressionVisitor visitor) 12 | { 13 | return visitor.Visit(this); 14 | } 15 | } 16 | 17 | public class Boolean : Expression 18 | { 19 | public bool Literal { get; set; } 20 | 21 | public Boolean(bool literal) 22 | { 23 | Literal = literal; 24 | } 25 | 26 | public override T Visit(IExpressionVisitor visitor) 27 | { 28 | return visitor.Visit(this); 29 | } 30 | } 31 | 32 | public class Number : Expression 33 | { 34 | public double Literal { get; set; } 35 | 36 | public Number(double literal) 37 | { 38 | Literal = literal; 39 | } 40 | 41 | public override T Visit(IExpressionVisitor visitor) 42 | { 43 | return visitor.Visit(this); 44 | } 45 | } 46 | 47 | public class String : Expression 48 | { 49 | public string Literal { get; set; } 50 | 51 | public String(string literal) 52 | { 53 | Literal = literal; 54 | } 55 | 56 | public override T Visit(IExpressionVisitor visitor) 57 | { 58 | return visitor.Visit(this); 59 | } 60 | } 61 | 62 | public class Varargs : Expression 63 | { 64 | public override T Visit(IExpressionVisitor visitor) 65 | { 66 | return visitor.Visit(this); 67 | } 68 | } 69 | 70 | public class Function : Expression 71 | { 72 | public FunctionBody Body { get; set; } 73 | 74 | public Function(FunctionBody body) 75 | { 76 | Body = body; 77 | } 78 | 79 | public override T Visit(IExpressionVisitor visitor) 80 | { 81 | return visitor.Visit(this); 82 | } 83 | } 84 | 85 | public class Prefix : Expression 86 | { 87 | public PrefixExpression Expression { get; set; } 88 | 89 | public Prefix(PrefixExpression expression) 90 | { 91 | Expression = expression; 92 | } 93 | 94 | public override T Visit(IExpressionVisitor visitor) 95 | { 96 | return visitor.Visit(this); 97 | } 98 | } 99 | 100 | public class Table : Expression 101 | { 102 | public List Fields { get; set; } 103 | 104 | public Table(List fields) 105 | { 106 | Fields = fields; 107 | } 108 | 109 | public override T Visit(IExpressionVisitor visitor) 110 | { 111 | return visitor.Visit(this); 112 | } 113 | } 114 | 115 | public class BinaryOp : Expression 116 | { 117 | public Ast.BinaryOp Operation { get; set; } 118 | public Expression Left { get; set; } 119 | public Expression Right { get; set; } 120 | 121 | public BinaryOp(Ast.BinaryOp operation, Expression left, Expression right) 122 | { 123 | Operation = operation; 124 | Left = left; 125 | Right = right; 126 | } 127 | 128 | public override T Visit(IExpressionVisitor visitor) 129 | { 130 | return visitor.Visit(this); 131 | } 132 | } 133 | 134 | public class UnaryOp : Expression 135 | { 136 | public Ast.UnaryOp Operation { get; set; } 137 | public Expression Operand { get; set; } 138 | 139 | public UnaryOp(Ast.UnaryOp operation, Expression operand) 140 | { 141 | Operation = operation; 142 | Operand = operand; 143 | } 144 | 145 | public override T Visit(IExpressionVisitor visitor) 146 | { 147 | return visitor.Visit(this); 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Field.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | abstract class Field : Node 4 | { 5 | public abstract T Visit(IFieldVisitor visitor); 6 | 7 | public class MemberExpr : Field 8 | { 9 | public Expression Member { get; set; } 10 | public Expression Value { get; set; } 11 | 12 | public MemberExpr(Expression member, Expression value) 13 | { 14 | Member = member; 15 | Value = value; 16 | } 17 | 18 | public override T Visit(IFieldVisitor visitor) 19 | { 20 | return visitor.Visit(this); 21 | } 22 | } 23 | 24 | public class MemberId : Field 25 | { 26 | public string Member { get; set; } 27 | public Expression Value { get; set; } 28 | 29 | public MemberId(string member, Expression value) 30 | { 31 | Member = member; 32 | Value = value; 33 | } 34 | 35 | public override T Visit(IFieldVisitor visitor) 36 | { 37 | return visitor.Visit(this); 38 | } 39 | } 40 | 41 | public class Normal : Field 42 | { 43 | public Expression Value { get; set; } 44 | 45 | public Normal(Expression value) 46 | { 47 | Value = value; 48 | } 49 | 50 | public override T Visit(IFieldVisitor visitor) 51 | { 52 | return visitor.Visit(this); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/FunctionBody.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | class FunctionBody : Node 6 | { 7 | public List Parameters { get; set; } 8 | public bool Varargs { get; set; } 9 | public Block Body { get; set; } 10 | 11 | public FunctionBody(List parameters, bool varargs, Block body) 12 | { 13 | Parameters = parameters; 14 | Varargs = varargs; 15 | Body = body; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/FunctionCall.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | abstract class FunctionCall : Node 4 | { 5 | public abstract T Visit(IFunctionCallVisitor visitor); 6 | 7 | public class Normal : FunctionCall 8 | { 9 | public PrefixExpression Prefix { get; set; } 10 | public Arguments Arguments { get; set; } 11 | 12 | public Normal(PrefixExpression prefix, Arguments arguments) 13 | { 14 | Prefix = prefix; 15 | Arguments = arguments; 16 | } 17 | 18 | public override T Visit(IFunctionCallVisitor visitor) 19 | { 20 | return visitor.Visit(this); 21 | } 22 | } 23 | 24 | public class Table : FunctionCall 25 | { 26 | public PrefixExpression Prefix { get; set; } 27 | public string Name { get; set; } 28 | public Arguments Arguments { get; set; } 29 | 30 | public Table(PrefixExpression prefix, string name, Arguments arguments) 31 | { 32 | Prefix = prefix; 33 | Name = name; 34 | Arguments = arguments; 35 | } 36 | 37 | public override T Visit(IFunctionCallVisitor visitor) 38 | { 39 | return visitor.Visit(this); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/FunctionName.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | class FunctionName : Node 6 | { 7 | public List Identifiers { get; set; } 8 | public string Table { get; set; } 9 | 10 | public FunctionName(List identifiers, string table) 11 | { 12 | Identifiers = identifiers; 13 | Table = table; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/IVisitor.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | interface IArgumentsVisitor 4 | { 5 | T Visit(Arguments.Normal arguments); 6 | T Visit(Arguments.String arguments); 7 | T Visit(Arguments.Table arguments); 8 | } 9 | 10 | interface IExpressionVisitor 11 | { 12 | T Visit(Expression.BinaryOp expression); 13 | T Visit(Expression.Boolean expression); 14 | T Visit(Expression.Function expression); 15 | T Visit(Expression.Nil expression); 16 | T Visit(Expression.Number expression); 17 | T Visit(Expression.Prefix expression); 18 | T Visit(Expression.String expression); 19 | T Visit(Expression.Table expression); 20 | T Visit(Expression.UnaryOp expression); 21 | T Visit(Expression.Varargs expression); 22 | } 23 | 24 | interface IFieldVisitor 25 | { 26 | T Visit(Field.MemberExpr field); 27 | T Visit(Field.MemberId field); 28 | T Visit(Field.Normal field); 29 | } 30 | 31 | interface IFunctionCallVisitor 32 | { 33 | T Visit(FunctionCall.Normal functionCall); 34 | T Visit(FunctionCall.Table functionCall); 35 | } 36 | 37 | interface ILastStatementVisitor 38 | { 39 | T Visit(LastStatement.Break lastStatement); 40 | T Visit(LastStatement.Return lastStatement); 41 | } 42 | 43 | interface IPrefixExpressionVisitor 44 | { 45 | T Visit(PrefixExpression.Expression prefixExpr); 46 | T Visit(PrefixExpression.FunctionCall prefixExpr); 47 | T Visit(PrefixExpression.Variable prefixExpr); 48 | } 49 | 50 | interface IStatementVisitor 51 | { 52 | T Visit(Statement.Assign statement); 53 | T Visit(Statement.Do statement); 54 | T Visit(Statement.For statement); 55 | T Visit(Statement.ForIn statement); 56 | T Visit(Statement.Function statement); 57 | T Visit(Statement.FunctionCall statement); 58 | T Visit(Statement.If statement); 59 | T Visit(Statement.LocalAssign statement); 60 | T Visit(Statement.LocalFunction statement); 61 | T Visit(Statement.Repeat statement); 62 | T Visit(Statement.While statement); 63 | } 64 | 65 | interface IVariableVisitor 66 | { 67 | T Visit(Variable.Identifier variable); 68 | T Visit(Variable.MemberExpr variable); 69 | T Visit(Variable.MemberId variable); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/LastStatement.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | abstract class LastStatement : Node 6 | { 7 | public abstract T Visit(ILastStatementVisitor visitor); 8 | 9 | public class Return : LastStatement 10 | { 11 | public List Values { get; set; } 12 | 13 | public Return(List values) 14 | { 15 | Values = values; 16 | } 17 | 18 | public override T Visit(ILastStatementVisitor visitor) 19 | { 20 | return visitor.Visit(this); 21 | } 22 | } 23 | 24 | public class Break : LastStatement 25 | { 26 | 27 | public override T Visit(ILastStatementVisitor visitor) 28 | { 29 | return visitor.Visit(this); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Node.cs: -------------------------------------------------------------------------------- 1 | using Expr = System.Linq.Expressions.Expression; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | abstract class Node 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/PrefixExpression.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | abstract class PrefixExpression : Node 4 | { 5 | public abstract T Visit(IPrefixExpressionVisitor visitor); 6 | 7 | public class Variable : PrefixExpression 8 | { 9 | public Ast.Variable Var { get; set; } 10 | 11 | public Variable(Ast.Variable variable) 12 | { 13 | Var = variable; 14 | } 15 | 16 | public override T Visit(IPrefixExpressionVisitor visitor) 17 | { 18 | return visitor.Visit(this); 19 | } 20 | } 21 | 22 | public class FunctionCall : PrefixExpression 23 | { 24 | public Ast.FunctionCall Call { get; set; } 25 | 26 | public FunctionCall(Ast.FunctionCall call) 27 | { 28 | Call = call; 29 | } 30 | 31 | public override T Visit(IPrefixExpressionVisitor visitor) 32 | { 33 | return visitor.Visit(this); 34 | } 35 | } 36 | 37 | public class Expression : PrefixExpression 38 | { 39 | public Ast.Expression Expr { get; set; } 40 | 41 | public Expression(Ast.Expression expression) 42 | { 43 | Expr = expression; 44 | } 45 | 46 | public override T Visit(IPrefixExpressionVisitor visitor) 47 | { 48 | return visitor.Visit(this); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Statement.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace IronLua.Compiler.Ast 4 | { 5 | abstract class Statement : Node 6 | { 7 | public abstract T Visit(IStatementVisitor visitor); 8 | 9 | public class Assign : Statement 10 | { 11 | public List Variables { get; set; } 12 | public List Values { get; set; } 13 | 14 | public Assign(List variables, List values) 15 | { 16 | Variables = variables; 17 | Values = values; 18 | } 19 | 20 | public override T Visit(IStatementVisitor visitor) 21 | { 22 | return visitor.Visit(this); 23 | } 24 | } 25 | 26 | public class FunctionCall : Statement 27 | { 28 | public Ast.FunctionCall Call { get; set; } 29 | 30 | public FunctionCall(Ast.FunctionCall call) 31 | { 32 | Call = call; 33 | } 34 | 35 | public override T Visit(IStatementVisitor visitor) 36 | { 37 | return visitor.Visit(this); 38 | } 39 | } 40 | 41 | public class Do : Statement 42 | { 43 | public Block Body { get; set; } 44 | 45 | public Do(Block body) 46 | { 47 | Body = body; 48 | } 49 | 50 | public override T Visit(IStatementVisitor visitor) 51 | { 52 | return visitor.Visit(this); 53 | } 54 | } 55 | 56 | public class While : Statement 57 | { 58 | public Expression Test { get; set; } 59 | public Block Body { get; set; } 60 | 61 | public While(Expression test, Block body) 62 | { 63 | Test = test; 64 | Body = body; 65 | } 66 | 67 | public override T Visit(IStatementVisitor visitor) 68 | { 69 | return visitor.Visit(this); 70 | } 71 | } 72 | 73 | public class Repeat : Statement 74 | { 75 | public Block Body { get; set; } 76 | public Expression Test { get; set; } 77 | 78 | public Repeat(Block body, Expression test) 79 | { 80 | Body = body; 81 | Test = test; 82 | } 83 | 84 | public override T Visit(IStatementVisitor visitor) 85 | { 86 | return visitor.Visit(this); 87 | } 88 | } 89 | 90 | public class If : Statement 91 | { 92 | public Expression Test { get; set; } 93 | public Block Body { get; set; } 94 | public List Elseifs { get; set; } 95 | public Block ElseBody { get; set; } 96 | 97 | public If(Expression test, Block body, List elseifs, Block elseBody) 98 | { 99 | Test = test; 100 | Body = body; 101 | Elseifs = elseifs; 102 | ElseBody = elseBody; 103 | } 104 | 105 | public override T Visit(IStatementVisitor visitor) 106 | { 107 | return visitor.Visit(this); 108 | } 109 | } 110 | 111 | public class For : Statement 112 | { 113 | public string Identifier { get; set; } 114 | public Expression Var { get; set; } 115 | public Expression Limit { get; set; } 116 | public Expression Step { get; set; } 117 | public Block Body { get; set; } 118 | 119 | public For(string indentifier, Expression var, Expression limit, Expression step, Block body) 120 | { 121 | Identifier = indentifier; 122 | Var = var; 123 | Limit = limit; 124 | Step = step; 125 | Body = body; 126 | } 127 | 128 | public override T Visit(IStatementVisitor visitor) 129 | { 130 | return visitor.Visit(this); 131 | } 132 | } 133 | 134 | public class ForIn : Statement 135 | { 136 | public List Identifiers { get; set; } 137 | public List Values { get; set; } 138 | public Block Body { get; set; } 139 | 140 | public ForIn(List identifiers, List values, Block body) 141 | { 142 | Identifiers = identifiers; 143 | Values = values; 144 | Body = body; 145 | } 146 | 147 | public override T Visit(IStatementVisitor visitor) 148 | { 149 | return visitor.Visit(this); 150 | } 151 | } 152 | 153 | public class Function : Statement 154 | { 155 | public FunctionName Name { get; set; } 156 | public FunctionBody Body { get; set; } 157 | 158 | public Function(FunctionName name, FunctionBody body) 159 | { 160 | Name = name; 161 | Body = body; 162 | } 163 | 164 | public override T Visit(IStatementVisitor visitor) 165 | { 166 | return visitor.Visit(this); 167 | } 168 | } 169 | 170 | public class LocalFunction : Statement 171 | { 172 | public string Identifier { get; set; } 173 | public FunctionBody Body { get; set; } 174 | 175 | public LocalFunction(string identifier, FunctionBody body) 176 | { 177 | Identifier = identifier; 178 | Body = body; 179 | } 180 | 181 | public override T Visit(IStatementVisitor visitor) 182 | { 183 | return visitor.Visit(this); 184 | } 185 | } 186 | 187 | public class LocalAssign : Statement 188 | { 189 | public List Identifiers { get; set; } 190 | public List Values { get; set; } 191 | 192 | public LocalAssign(List identifiers, List values) 193 | { 194 | Identifiers = identifiers; 195 | Values = values; 196 | } 197 | 198 | public override T Visit(IStatementVisitor visitor) 199 | { 200 | return visitor.Visit(this); 201 | } 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/UnaryOp.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | enum UnaryOp 4 | { 5 | Not, 6 | Length, 7 | Negate 8 | } 9 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Ast/Variable.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Ast 2 | { 3 | abstract class Variable : Node 4 | { 5 | public abstract T Visit(IVariableVisitor visitor); 6 | 7 | public class Identifier : Variable 8 | { 9 | public string Value { get; set; } 10 | 11 | public Identifier(string value) 12 | { 13 | Value = value; 14 | } 15 | 16 | public override T Visit(IVariableVisitor visitor) 17 | { 18 | return visitor.Visit(this); 19 | } 20 | } 21 | 22 | public class MemberExpr : Variable 23 | { 24 | public PrefixExpression Prefix { get; set; } 25 | public Expression Member { get; set; } 26 | 27 | public MemberExpr(PrefixExpression prefix, Expression member) 28 | { 29 | Prefix = prefix; 30 | Member = member; 31 | } 32 | 33 | public override T Visit(IVariableVisitor visitor) 34 | { 35 | return visitor.Visit(this); 36 | } 37 | } 38 | 39 | public class MemberId : Variable 40 | { 41 | public PrefixExpression Prefix { get; set; } 42 | public string Member { get; set; } 43 | 44 | public MemberId(PrefixExpression prefix, string member) 45 | { 46 | Prefix = prefix; 47 | Member = member; 48 | } 49 | 50 | public override T Visit(IVariableVisitor visitor) 51 | { 52 | return visitor.Visit(this); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IronLua/Compiler/ExprHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IronLua.Runtime; 3 | using Expr = System.Linq.Expressions.Expression; 4 | 5 | namespace IronLua.Compiler 6 | { 7 | static class ExprHelpers 8 | { 9 | public static Expr ConvertToBoolean(Context context, Expr expression) 10 | { 11 | var convertBinder = Context.DynamicCache.GetConvertBinder(typeof(bool)); 12 | return Expr.Dynamic(convertBinder, typeof(bool), expression); 13 | } 14 | 15 | public static Expr ConvertToNumber(Context context, Expr expression) 16 | { 17 | var convertBinder = Context.DynamicCache.GetConvertBinder(typeof(double)); 18 | return Expr.Dynamic(convertBinder, typeof(double), expression); 19 | } 20 | 21 | public static Expr CheckNumberForNan(Expr number, string format, params object[] args) 22 | { 23 | return Expr.IfThen( 24 | Expr.Invoke(Expr.Constant((Func)Double.IsNaN), number), 25 | Expr.Throw(Expr.New(MemberInfos.NewRuntimeException, Expr.Constant(format), Expr.Constant(args)))); 26 | } 27 | 28 | public static Expr ConvertToNumberAndCheck(Context context, Expr expression, string format, params object[] args) 29 | { 30 | var numberVar = Expr.Variable(typeof(double)); 31 | var assignNumber = Expr.Assign(numberVar, ConvertToNumber(context, expression)); 32 | 33 | return Expr.Block( 34 | new[] {numberVar}, 35 | assignNumber, 36 | Expr.Condition( 37 | Expr.Invoke( 38 | Expr.Constant((Func)Double.IsNaN), numberVar), 39 | Expr.Block( 40 | Expr.Throw(Expr.New(MemberInfos.NewRuntimeException, Expr.Constant(format), Expr.Constant(args))), 41 | Expr.Constant(Double.NaN)), 42 | numberVar)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /IronLua/Compiler/FieldVisit.cs: -------------------------------------------------------------------------------- 1 | using Expr = System.Linq.Expressions.Expression; 2 | 3 | namespace IronLua.Compiler 4 | { 5 | class FieldVisit 6 | { 7 | public FieldVisitType Type { get; private set; } 8 | public Expr Member { get; private set; } 9 | public Expr Value { get; private set; } 10 | 11 | private FieldVisit() 12 | { 13 | } 14 | 15 | public static FieldVisit CreateImplicit(Expr value) 16 | { 17 | return new FieldVisit 18 | { 19 | Type = FieldVisitType.Implicit, 20 | Value = value 21 | }; 22 | } 23 | 24 | public static FieldVisit CreateExplicit(Expr member, Expr value) 25 | { 26 | return new FieldVisit 27 | { 28 | Type = FieldVisitType.Explicit, 29 | Member = member, 30 | Value = value 31 | }; 32 | } 33 | } 34 | 35 | enum FieldVisitType 36 | { 37 | Implicit, 38 | Explicit 39 | } 40 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Parser/Input.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace IronLua.Compiler.Parser 5 | { 6 | class Input 7 | { 8 | readonly string source; 9 | int index; 10 | 11 | public string File { get; private set; } 12 | public int Line { get; private set; } 13 | public int Column { get; private set; } 14 | 15 | int storedLine; 16 | int storedColumn; 17 | readonly StringBuilder buffer; 18 | 19 | public Input(string source) 20 | { 21 | this.source = source; 22 | File = ""; 23 | index = 0; 24 | buffer = new StringBuilder(1024); 25 | } 26 | 27 | public char Current 28 | { 29 | get 30 | { 31 | try 32 | { 33 | return source[index]; 34 | } 35 | catch (IndexOutOfRangeException e) 36 | { 37 | throw new LuaSyntaxException(this, ExceptionMessage.UNEXPECTED_EOF, e); 38 | } 39 | } 40 | } 41 | 42 | public char Peek 43 | { 44 | get 45 | { 46 | try 47 | { 48 | return source[index + 1]; 49 | } 50 | catch (IndexOutOfRangeException e) 51 | { 52 | throw new LuaSyntaxException(this, ExceptionMessage.UNEXPECTED_EOF, e); 53 | } 54 | } 55 | } 56 | 57 | public bool CanContinue 58 | { 59 | get { return index < source.Length; } 60 | } 61 | 62 | public bool CanPeek 63 | { 64 | get { return index + 1 < source.Length; } 65 | } 66 | 67 | public string Buffer 68 | { 69 | get { return buffer.ToString(); } 70 | } 71 | 72 | public void Advance() 73 | { 74 | index += 1; 75 | Column = Column + 1; 76 | } 77 | 78 | public void Back() 79 | { 80 | index -= 1; 81 | Column = Column - 1; 82 | } 83 | 84 | public void StorePosition() 85 | { 86 | storedLine = Line; 87 | storedColumn = Column; 88 | } 89 | 90 | public void Newline() 91 | { 92 | Line += 1; 93 | Column = 1; 94 | } 95 | 96 | public void BufferAppend(char c) 97 | { 98 | buffer.Append(c); 99 | } 100 | 101 | public void BufferAppend(string str) 102 | { 103 | buffer.Append(str); 104 | } 105 | 106 | public void BufferRemove(int length) 107 | { 108 | buffer.Remove(buffer.Length - length, length); 109 | } 110 | 111 | public void BufferRemove(int start, int length) 112 | { 113 | buffer.Remove(start, length); 114 | } 115 | 116 | public void BufferClear() 117 | { 118 | buffer.Clear(); 119 | } 120 | 121 | public Token Output(Symbol symbol) 122 | { 123 | return new Token(symbol, Line, Column); 124 | } 125 | 126 | public Token OutputBuffer(Symbol symbol) 127 | { 128 | return new Token(symbol, storedLine, storedColumn, buffer.ToString()); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /IronLua/Compiler/Parser/Lexer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using IronLua.Util; 3 | 4 | namespace IronLua.Compiler.Parser 5 | { 6 | class Lexer 7 | { 8 | static readonly Dictionary keywords = 9 | new Dictionary 10 | { 11 | {"and", Symbol.And}, 12 | {"break", Symbol.Break}, 13 | {"do", Symbol.Do}, 14 | {"else", Symbol.Else}, 15 | {"elseif", Symbol.Elseif}, 16 | {"end", Symbol.End}, 17 | {"false", Symbol.False}, 18 | {"for", Symbol.For}, 19 | {"function", Symbol.Function}, 20 | {"if", Symbol.If}, 21 | {"in", Symbol.In}, 22 | {"local", Symbol.Local}, 23 | {"nil", Symbol.Nil}, 24 | {"not", Symbol.Not}, 25 | {"or", Symbol.Or}, 26 | {"repeat", Symbol.Repeat}, 27 | {"return", Symbol.Return}, 28 | {"then", Symbol.Then}, 29 | {"true", Symbol.True}, 30 | {"until", Symbol.Until}, 31 | {"while", Symbol.While} 32 | }; 33 | 34 | readonly Input input; 35 | 36 | public Token Last { get; private set; } 37 | public Token Current { get; private set; } 38 | public Token Next { get; private set; } 39 | 40 | public Lexer(Input input) 41 | { 42 | this.input = input; 43 | Current = NextToken(); 44 | Next = NextToken(); 45 | } 46 | 47 | public void Consume() 48 | { 49 | Last = Current; 50 | Current = Next; 51 | Next = NextToken(); 52 | } 53 | 54 | public string ConsumeLexeme() 55 | { 56 | var lexeme = Current.Lexeme; 57 | Consume(); 58 | return lexeme; 59 | } 60 | 61 | public bool TryConsume(Symbol symbol) 62 | { 63 | if (Current.Symbol == symbol) 64 | { 65 | Consume(); 66 | return true; 67 | } 68 | return false; 69 | } 70 | 71 | public void Expect(Symbol symbol) 72 | { 73 | if (Current.Symbol == symbol) 74 | Consume(); 75 | else 76 | throw new LuaSyntaxException(input, ExceptionMessage.EXPECTED_SYMBOL, Current.Symbol, symbol); 77 | } 78 | 79 | public string ExpectLexeme(Symbol symbol) 80 | { 81 | var lexeme = Current.Lexeme; 82 | Expect(symbol); 83 | return lexeme; 84 | } 85 | 86 | private Token NextToken() 87 | { 88 | while (input.CanContinue) 89 | { 90 | switch (input.Current) 91 | { 92 | // Whitespace 93 | case ' ': case '\t': 94 | input.Advance(); 95 | break; 96 | 97 | // Newlines 98 | case '\r': case '\n': 99 | NextLine(); 100 | break; 101 | 102 | // String 103 | case '\'': case '"': 104 | return StringLiteral(input.Current); 105 | 106 | // Comment or minus 107 | case '-': 108 | input.StorePosition(); 109 | input.Advance(); 110 | 111 | if (input.Current != '-') 112 | return input.Output(Symbol.Minus); 113 | 114 | if (input.CanPeek && input.Peek == '[') 115 | LongComment(); 116 | else 117 | ShortComment(); 118 | 119 | break; 120 | 121 | default: 122 | // Long string 123 | if (input.Current == '[' && input.CanPeek && 124 | (input.Peek == '[' || input.Peek == '=')) 125 | return LongStringLiteral(); 126 | 127 | // Hex numeric 128 | if (input.Current == '0' && input.CanPeek && 129 | (input.Peek == 'X' || input.Peek == 'x')) 130 | return NumericHexLiteral(); 131 | 132 | // Numeric 133 | if (input.Current.IsDecimal() || 134 | (input.Current == '.' && input.CanPeek && input.Peek.IsDecimal())) 135 | return NumericLiteral(); 136 | 137 | // Identifier or keyword 138 | if (input.Current.IsIdentifierStart()) 139 | return IdentifierOrKeyword(); 140 | 141 | // Punctuation 142 | if (input.Current.IsPunctuation()) 143 | return Punctuation(); 144 | 145 | throw new LuaSyntaxException(input, ExceptionMessage.UNEXPECTED_CHAR, input.Current); 146 | 147 | } 148 | } 149 | return input.Output(Symbol.Eof); 150 | } 151 | 152 | /* Identifier or keyword */ 153 | Token IdentifierOrKeyword() 154 | { 155 | input.StorePosition(); 156 | input.BufferClear(); 157 | 158 | while (input.CanContinue && input.Current.IsIdentifier()) 159 | { 160 | input.BufferAppend(input.Current); 161 | input.Advance(); 162 | } 163 | 164 | // Keyword or identifier? 165 | Symbol symbol; 166 | if (keywords.TryGetValue(input.Buffer, out symbol)) 167 | return input.Output(symbol); 168 | return input.OutputBuffer(Symbol.Identifier); 169 | } 170 | 171 | /* Numeric literal, such as 12345 or 45e+1 */ 172 | Token NumericLiteral() 173 | { 174 | input.StorePosition(); 175 | input.BufferClear(); 176 | 177 | while (input.CanContinue) 178 | { 179 | if (input.Current == 'e' || input.Current == 'E') 180 | { 181 | BufferExponent(); 182 | break; 183 | } 184 | if (input.Current.IsDecimal() || input.Current == '.') 185 | input.BufferAppend(input.Current); 186 | else 187 | break; 188 | 189 | input.Advance(); 190 | } 191 | 192 | return input.OutputBuffer(Symbol.Number); 193 | } 194 | 195 | /* Buffers the exponent part of a numeric literal, 196 | * such as e+5 p8 e2 */ 197 | void BufferExponent() 198 | { 199 | input.BufferAppend(input.Current); 200 | input.Advance(); 201 | 202 | if (input.CanContinue && (input.Current == '-' || input.Current == '+')) 203 | { 204 | input.BufferAppend(input.Current); 205 | input.Advance(); 206 | } 207 | 208 | while (input.CanContinue && input.Current.IsDecimal()) 209 | { 210 | input.BufferAppend(input.Current); 211 | input.Advance(); 212 | } 213 | } 214 | 215 | /* Hex literal, such as 0xFF or 0x10p4 216 | * Can be malformed, parser handles that */ 217 | Token NumericHexLiteral() 218 | { 219 | input.StorePosition(); 220 | input.BufferClear(); 221 | input.BufferAppend("0x"); 222 | input.Advance(); 223 | 224 | while (input.CanContinue) 225 | { 226 | if (input.Current == 'p' || input.Current == 'P') 227 | { 228 | BufferExponent(); 229 | break; 230 | } 231 | if (input.Current.IsHex()) 232 | input.BufferAppend(input.Current); 233 | else 234 | break; 235 | 236 | input.Advance(); 237 | } 238 | 239 | return input.OutputBuffer(Symbol.Number); 240 | } 241 | 242 | /* Long string literal, such as [[bla bla]] */ 243 | Token LongStringLiteral() 244 | { 245 | input.StorePosition(); 246 | input.BufferClear(); 247 | 248 | int numEqualsStart = CountEquals(); 249 | if (input.Current != '[') 250 | throw new LuaSyntaxException(input, ExceptionMessage.INVALID_LONG_STRING_DELIMTER, input.Current); 251 | 252 | // Skip immediately following newline 253 | if (input.Current == '\r' || input.Current == '\n') 254 | NextLine(); 255 | 256 | while (true) 257 | { 258 | while (input.Current != ']') 259 | input.Advance(); 260 | 261 | input.Advance(); 262 | int numEqualsEnd = CountEquals(); 263 | 264 | // Output string if matching ='s found 265 | 266 | if (numEqualsStart == numEqualsEnd && input.Current == ']') 267 | { 268 | // Trim long string delimters 269 | input.BufferRemove(0, numEqualsStart); 270 | input.BufferRemove(numEqualsEnd + 1); 271 | input.Advance(); 272 | return input.OutputBuffer(Symbol.String); 273 | } 274 | if (input.Current == ']') 275 | // Parse ']' again because it can be the start of another long string delimeter 276 | input.Back(); 277 | else 278 | input.BufferAppend(input.Current); 279 | } 280 | } 281 | 282 | /* Count amount of continous '=' */ 283 | int CountEquals() 284 | { 285 | int count = 0; 286 | while (input.Current == '=') 287 | { 288 | count++; 289 | input.Advance(); 290 | } 291 | 292 | return count; 293 | } 294 | 295 | /* Long comment, such as --[[bla bla bla]] */ 296 | void LongComment() 297 | { 298 | input.Advance(); 299 | int numEqualsStart = CountEquals(); 300 | if (input.Current != '[') 301 | throw new LuaSyntaxException(input, ExceptionMessage.INVALID_LONG_STRING_DELIMTER, input.Current); 302 | 303 | while (true) 304 | { 305 | while (input.Current != ']') 306 | input.Advance(); 307 | 308 | input.Advance(); 309 | int numEqualsEnd = CountEquals(); 310 | 311 | if (numEqualsStart == numEqualsEnd && input.Current == ']') 312 | { 313 | input.Advance(); 314 | break; 315 | } 316 | // Parse ']' again because it can be the start of another long comment delimeter 317 | if (input.Current == ']') 318 | input.Back(); 319 | 320 | } 321 | } 322 | 323 | /* Short comment, such as --bla bla */ 324 | void ShortComment() 325 | { 326 | while (input.CanContinue && input.Current != '\r' && input.Current != '\n') 327 | input.Advance(); 328 | } 329 | 330 | Token Punctuation() 331 | { 332 | char c = input.Current; 333 | input.Advance(); 334 | switch (c) 335 | { 336 | case '+': 337 | return input.Output(Symbol.Plus); 338 | case '-': 339 | return input.Output(Symbol.Minus); 340 | case '*': 341 | return input.Output(Symbol.Star); 342 | case '/': 343 | return input.Output(Symbol.Slash); 344 | case '%': 345 | return input.Output(Symbol.Percent); 346 | case '^': 347 | return input.Output(Symbol.Caret); 348 | case '#': 349 | return input.Output(Symbol.Hash); 350 | case '~': 351 | return input.Current == '=' ? LongPunctuation(c) : input.Output(Symbol.TildeEqual); 352 | case '<': 353 | return input.Current == '=' ? LongPunctuation(c) : input.Output(Symbol.Less); 354 | case '>': 355 | return input.Current == '=' ? LongPunctuation(c) : input.Output(Symbol.Greater); 356 | case '=': 357 | return input.Current == '=' ? LongPunctuation(c) : input.Output(Symbol.Equal); 358 | case '(': 359 | return input.Output(Symbol.LeftParen); 360 | case ')': 361 | return input.Output(Symbol.RightParen); 362 | case '{': 363 | return input.Output(Symbol.LeftBrace); 364 | case '}': 365 | return input.Output(Symbol.RightBrace); 366 | case '[': 367 | return input.Output(Symbol.LeftBrack); 368 | case ']': 369 | return input.Output(Symbol.RightBrack); 370 | case ';': 371 | return input.Output(Symbol.SemiColon); 372 | case ':': 373 | return input.Output(Symbol.Colon); 374 | case ',': 375 | return input.Output(Symbol.Comma); 376 | case '.': 377 | return input.Current == '.' ? LongPunctuation(c) : input.Output(Symbol.Dot); 378 | default: 379 | throw new LuaSyntaxException(input, ExceptionMessage.UNKNOWN_PUNCTUATION, c); 380 | } 381 | } 382 | 383 | Token LongPunctuation(char c1) 384 | { 385 | char c2 = input.Current; 386 | input.Advance(); 387 | 388 | switch(c1) 389 | { 390 | case '~': 391 | if (c2 == '=') return input.Output(Symbol.TildeEqual); 392 | break; 393 | case '<': 394 | if (c2 == '=') return input.Output(Symbol.LessEqual); 395 | break; 396 | case '>': 397 | if (c2 == '=') return input.Output(Symbol.GreaterEqual); 398 | break; 399 | case '=': 400 | if (c2 == '=') return input.Output(Symbol.EqualEqual); 401 | break; 402 | case '.': 403 | if (c2 == '.') 404 | { 405 | if (input.Current == '.') 406 | { 407 | input.Advance(); 408 | return input.Output(Symbol.DotDotDot); 409 | } 410 | return input.Output(Symbol.DotDot); 411 | } 412 | break; 413 | } 414 | 415 | throw new LuaSyntaxException(input, ExceptionMessage.UNKNOWN_PUNCTUATION, "" + c1 + c2); 416 | } 417 | 418 | /* String literal, such as "bla bla" */ 419 | Token StringLiteral(char end) 420 | { 421 | input.StorePosition(); 422 | input.BufferClear(); 423 | 424 | while (true) 425 | { 426 | input.Advance(); 427 | 428 | switch (input.Current) 429 | { 430 | case '\\': 431 | input.Advance(); 432 | 433 | switch (input.Current) 434 | { 435 | case 'a': input.BufferAppend('\a'); break; 436 | case 'b': input.BufferAppend('\b'); break; 437 | case 'f': input.BufferAppend('\f'); break; 438 | case 'n': input.BufferAppend('\n'); break; 439 | case 'r': input.BufferAppend('\r'); break; 440 | case 't': input.BufferAppend('\t'); break; 441 | case '\"': input.BufferAppend('\"'); break; 442 | case '\'': input.BufferAppend('\''); break; 443 | case '\\': input.BufferAppend('\\'); break; 444 | case '\r': input.BufferAppend('\r'); NextLine(); break; 445 | case '\n': input.BufferAppend('\n'); NextLine(); break; 446 | default: 447 | if (input.Current.IsDecimal()) 448 | BufferNumericEscape(); 449 | else 450 | // Lua manual says only the above chars can be escaped 451 | // but Luac allows any char to be escaped 452 | input.BufferAppend(input.Current); 453 | break; 454 | } 455 | break; 456 | 457 | case '\r': case '\n': 458 | throw new LuaSyntaxException(input, ExceptionMessage.UNEXPECTED_EOS); 459 | 460 | default: 461 | if (input.Current == end) 462 | { 463 | input.Advance(); 464 | return input.OutputBuffer(Symbol.String); 465 | } 466 | 467 | input.BufferAppend(input.Current); 468 | break; 469 | } 470 | } 471 | } 472 | 473 | /* Buffer a numeric escape, such as \012 or \9 */ 474 | void BufferNumericEscape() 475 | { 476 | int value = 0; 477 | 478 | for (int i = 0; i < 3; i++) 479 | { 480 | if (!input.Current.IsDecimal()) 481 | break; 482 | 483 | value = value*10 + input.Current - '0'; 484 | input.Advance(); 485 | } 486 | 487 | input.BufferAppend((char)value); 488 | } 489 | 490 | /* New line, such as \r, \n or \r\n */ 491 | void NextLine() 492 | { 493 | if (input.Current == '\r' && input.CanPeek && input.Peek == '\n') 494 | input.Advance(); 495 | input.Advance(); 496 | input.Newline(); 497 | } 498 | } 499 | } 500 | -------------------------------------------------------------------------------- /IronLua/Compiler/Parser/Symbol.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Parser 2 | { 3 | enum Symbol 4 | { 5 | // Keywords 6 | And, 7 | Break, 8 | Do, 9 | Else, 10 | Elseif, 11 | End, 12 | False, 13 | For, 14 | Function, 15 | If, 16 | In, 17 | Local, 18 | Nil, 19 | Not, 20 | Or, 21 | Repeat, 22 | Return, 23 | Then, 24 | True, 25 | Until, 26 | While, 27 | 28 | // Punctuations 29 | Plus, 30 | Minus, 31 | Star, 32 | Slash, 33 | Percent, 34 | Caret, 35 | Hash, 36 | EqualEqual, 37 | TildeEqual, 38 | LessEqual, 39 | GreaterEqual, 40 | Less, 41 | Greater, 42 | Equal, 43 | LeftParen, 44 | RightParen, 45 | LeftBrace, 46 | RightBrace, 47 | LeftBrack, 48 | RightBrack, 49 | SemiColon, 50 | Colon, 51 | Comma, 52 | Dot, 53 | DotDot, 54 | DotDotDot, 55 | 56 | // Literals 57 | Number, 58 | String, 59 | Identifier, 60 | 61 | // Markers 62 | Eof 63 | } 64 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Parser/Token.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Compiler.Parser 2 | { 3 | class Token 4 | { 5 | public Symbol Symbol { get; private set; } 6 | public int Line { get; private set; } 7 | public int Column { get; private set; } 8 | public string Lexeme { get; private set; } 9 | 10 | public Token(Symbol symbol, int line, int column, string lexeme = null) 11 | { 12 | Symbol = symbol; 13 | Lexeme = lexeme; 14 | Line = line; 15 | Column = column; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /IronLua/Compiler/Scope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using Expr = System.Linq.Expressions.Expression; 5 | using ParamExpr = System.Linq.Expressions.ParameterExpression; 6 | 7 | namespace IronLua.Compiler 8 | { 9 | class Scope 10 | { 11 | Scope parent; 12 | readonly Dictionary variables; 13 | LabelTarget breakLabel; 14 | LabelTarget returnLabel; 15 | 16 | public bool IsRoot { get { return parent == null; } } 17 | 18 | private Scope() 19 | { 20 | variables = new Dictionary(); 21 | } 22 | 23 | public ParamExpr[] AllLocals() 24 | { 25 | var values = variables.Values; 26 | var array = new ParamExpr[values.Count]; 27 | values.CopyTo(array, 0); 28 | return array; 29 | } 30 | 31 | public bool TryGetLocal(string name, out ParamExpr local) 32 | { 33 | if (variables.TryGetValue(name, out local)) 34 | return true; 35 | if (parent != null) 36 | return parent.TryGetLocal(name, out local); 37 | 38 | return false; 39 | } 40 | 41 | public ParamExpr AddLocal(string name, Type type = null) 42 | { 43 | // We have this behavior so that ex. "local x, x = 1, 2" works 44 | ParamExpr param; 45 | if (!variables.TryGetValue(name, out param)) 46 | variables.Add(name, param = Expr.Variable(type ?? typeof(object))); 47 | 48 | return param; 49 | } 50 | 51 | public LabelTarget BreakLabel() 52 | { 53 | return breakLabel ?? (breakLabel = Expr.Label()); 54 | } 55 | 56 | public static Scope CreateRoot() 57 | { 58 | return new Scope { returnLabel = Expr.Label(typeof(object)) }; 59 | } 60 | 61 | public static Scope CreateChild(Scope parent) 62 | { 63 | return new Scope 64 | { 65 | parent = parent, 66 | breakLabel = parent.breakLabel 67 | }; 68 | } 69 | 70 | public static Scope CreateFunctionChild(Scope parent) 71 | { 72 | return new Scope 73 | { 74 | parent = parent, 75 | returnLabel = Expr.Label(typeof(object)) 76 | }; 77 | } 78 | 79 | public LabelTarget GetReturnLabel() 80 | { 81 | if (returnLabel != null) 82 | return returnLabel; 83 | if (parent == null) 84 | return null; 85 | return parent.GetReturnLabel(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /IronLua/Compiler/VariableVisit.cs: -------------------------------------------------------------------------------- 1 | using Expr = System.Linq.Expressions.Expression; 2 | 3 | namespace IronLua.Compiler 4 | { 5 | class VariableVisit 6 | { 7 | public VariableType Type { get; private set; } 8 | public Expr Object { get; private set; } 9 | public string Identifier { get; private set; } 10 | public Expr Member { get; private set; } 11 | 12 | private VariableVisit() 13 | { 14 | } 15 | 16 | public static VariableVisit CreateIdentifier(string identifier) 17 | { 18 | return new VariableVisit 19 | { 20 | Type = VariableType.Identifier, 21 | Identifier = identifier 22 | }; 23 | } 24 | 25 | public static VariableVisit CreateMemberId(Expr @object, string identifier) 26 | { 27 | return new VariableVisit 28 | { 29 | Type = VariableType.MemberId, 30 | Object = @object, 31 | Identifier = identifier 32 | }; 33 | } 34 | 35 | public static VariableVisit CreateMemberExpr(Expr @object, Expr member) 36 | { 37 | return new VariableVisit 38 | { 39 | Type = VariableType.MemberExpr, 40 | Object = @object, 41 | Member = member 42 | }; 43 | } 44 | } 45 | 46 | enum VariableType 47 | { 48 | Identifier, 49 | MemberId, 50 | MemberExpr 51 | } 52 | } -------------------------------------------------------------------------------- /IronLua/Constant.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Globalization; 3 | using ExprType = System.Linq.Expressions.ExpressionType; 4 | 5 | namespace IronLua 6 | { 7 | static class Constant 8 | { 9 | public static readonly CultureInfo INVARIANT_CULTURE = CultureInfo.InvariantCulture; 10 | 11 | // Only includes metamethods that can be translated from ExprTypes 12 | public static readonly Dictionary METAMETHODS = 13 | new Dictionary 14 | { 15 | {ExprType.NotEqual, "__eq"}, 16 | {ExprType.GreaterThan, "__lt"}, 17 | {ExprType.GreaterThanOrEqual, "__le"}, 18 | 19 | {ExprType.Equal, "__eq"}, 20 | {ExprType.LessThan, "__lt"}, 21 | {ExprType.LessThanOrEqual, "__le"}, 22 | {ExprType.Add, "__add"}, 23 | {ExprType.Subtract, "__sub"}, 24 | {ExprType.Multiply, "__mul"}, 25 | {ExprType.Divide, "__div"}, 26 | {ExprType.Modulo, "__mod"}, 27 | {ExprType.Power, "__pow"} 28 | }; 29 | 30 | public const string LUA_VERSION = "Lua 5.1"; 31 | 32 | public const string CONCAT_METAMETHOD = "__concat"; 33 | public const string LENGTH_METAMETHOD = "__len"; 34 | public const string UNARYMINUS_METAMETHOD = "__unm"; 35 | public const string INDEX_METAMETHOD = "__index"; 36 | public const string NEWINDEX_METAMETHOD = "__newindex"; 37 | public const string CALL_METAMETHOD = "__call"; 38 | public const string METATABLE_METAFIELD = "__metatable"; 39 | public const string TOSTRING_METAFIELD = "__tostring"; 40 | 41 | public const string VARARGS = "$varargs$"; 42 | public const string FUNCTION_PREFIX = "lua$"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /IronLua/ExceptionMessage.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua 2 | { 3 | static class ExceptionMessage 4 | { 5 | // Syntax 6 | public const string UNEXPECTED_EOF = "Unexpected end of file"; 7 | public const string UNEXPECTED_EOS = "Unexpected end of string"; 8 | public const string UNEXPECTED_CHAR = "Unexpected '{0}'"; 9 | public const string UNKNOWN_PUNCTUATION = "Unknown punctuation '{0}'"; 10 | public const string INVALID_LONG_STRING_DELIMTER = "Invalid long string delimter '{0}'"; 11 | public const string UNEXPECTED_SYMBOL = "Unexpected symbol '{0}'"; 12 | public const string EXPECTED_SYMBOL = "Unexpected symbol '{0}', expected '{1}'"; 13 | public const string MALFORMED_NUMBER = "Malformed number '{0}'"; 14 | public const string AMBIGUOUS_SYNTAX_FUNCTION_CALL = "Ambiguous syntax (function call or new statement)"; 15 | 16 | // Runtime 17 | public const string FOR_VALUE_NOT_NUMBER = "For loop {0} must be a number"; 18 | public const string OP_TYPE_ERROR = "Attempt to {0} a {1} value"; 19 | public const string OP_TYPE_WITH_ERROR = "Attempt to {0} {1} with {2}"; 20 | public const string OP_TYPE_TWO_ERROR = "Attempt to {0} two {1} values"; 21 | // TODO: Add "to '...'" when we implement call stacks 22 | public const string INVOKE_BAD_ARGUMENT = "Bad argument #{0} ({1})"; 23 | public const string INVOKE_BAD_ARGUMENT_EXPECTED = "Bad argument #{0} ({1} expected)"; 24 | public const string INVOKE_BAD_ARGUMENT_GOT = "Bad argument #{0} ({1} expected, got {2})"; 25 | 26 | // Library 27 | //public const string BAD_ARGUMENT_INVALID_OPTION = "Bad argument #{0} to '{1}' (invalid option '{2}')"; 28 | public const string STRING_FORMAT_INVALID_OPTION = "Invalid option '{0}', to 'format'"; 29 | public const string FUNCTION_NOT_IMPLEMENTED = "Function '{0}' not implemented"; 30 | public const string PROTECTED_METATABLE = "Cannot change a protected metatable"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IronLua/IronLua.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {F166178F-729B-4DB5-8D7C-13C269FB5039} 9 | Library 10 | Properties 11 | IronLua 12 | IronLua 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 119 | -------------------------------------------------------------------------------- /IronLua/Library/BaseLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using IronLua.Compiler; 7 | using IronLua.Compiler.Parser; 8 | using IronLua.Runtime; 9 | using IronLua.Runtime.Binder; 10 | 11 | namespace IronLua.Library 12 | { 13 | class BaseLibrary : Library 14 | { 15 | public BaseLibrary(Context context) : base(context) 16 | { 17 | } 18 | 19 | public static Varargs Assert(bool v, object message = null, params object[] additional) 20 | { 21 | if (v) 22 | { 23 | var returnValues = new List(2 + additional.Length) {true}; 24 | if (message != null) 25 | returnValues.Add(message); 26 | returnValues.AddRange(additional); 27 | return new Varargs(returnValues); 28 | } 29 | 30 | if (message == null) 31 | throw new LuaRuntimeException("Assertion failed"); 32 | throw new LuaRuntimeException(message.ToString()); 33 | } 34 | 35 | public void CollectGarbage(string opt, string arg = null) 36 | { 37 | throw new LuaRuntimeException(ExceptionMessage.FUNCTION_NOT_IMPLEMENTED); 38 | } 39 | 40 | public object DoFile(string filename = null) 41 | { 42 | var source = filename == null ? Console.In.ReadToEnd() : File.ReadAllText(filename); 43 | try 44 | { 45 | return CompileString(source)(); 46 | } 47 | catch (LuaSyntaxException e) 48 | { 49 | throw new LuaRuntimeException(e.Message, e); 50 | } 51 | } 52 | 53 | public static void Error(string message, object level) 54 | { 55 | // TODO: Use level when call stacks are implemented 56 | throw new LuaRuntimeException(message); 57 | } 58 | 59 | public object GetFEnv(object f = null) 60 | { 61 | throw new LuaRuntimeException(ExceptionMessage.FUNCTION_NOT_IMPLEMENTED); 62 | } 63 | 64 | public object GetMetatable(object obj) 65 | { 66 | LuaTable table; 67 | 68 | if ((table = obj as LuaTable) != null) 69 | table = table.Metatable; 70 | if (table == null) 71 | table = Context.GetTypeMetatable(obj); 72 | if (table == null) 73 | return null; 74 | 75 | var table2 = table.GetValue(Constant.METATABLE_METAFIELD); 76 | return table2 ?? table; 77 | } 78 | 79 | public static Varargs IPairs(LuaTable t) 80 | { 81 | var length = t.Length(); 82 | Func func = 83 | index => 84 | { 85 | index++; 86 | return index > length ? null : new Varargs(index, t.GetValue(index)); 87 | }; 88 | 89 | return new Varargs(func, t, 0.0); 90 | } 91 | 92 | public Varargs Load(Delegate func, string chunkname = "=(load)") 93 | { 94 | var invoker = Context.DynamicCache.GetDynamicCall0(); 95 | var sb = new StringBuilder(1024); 96 | 97 | while (true) 98 | { 99 | var result = invoker(func); 100 | if (result == null) 101 | break; 102 | 103 | var str = result.ToString(); 104 | if (String.IsNullOrEmpty(str)) 105 | break; 106 | 107 | sb.Append(str); 108 | } 109 | 110 | try 111 | { 112 | return new Varargs(CompileString(sb.ToString())); 113 | } 114 | catch (LuaSyntaxException e) 115 | { 116 | return new Varargs(null, e.Message); 117 | } 118 | } 119 | 120 | public Varargs LoadFile(string filename = null) 121 | { 122 | var source = filename == null ? Console.In.ReadToEnd() : File.ReadAllText(filename); 123 | try 124 | { 125 | return new Varargs(CompileString(source)); 126 | } 127 | catch (LuaSyntaxException e) 128 | { 129 | return new Varargs(null, e.Message); 130 | } 131 | } 132 | 133 | public Varargs LoadString(string str, string chunkname = "=(loadstring)") 134 | { 135 | try 136 | { 137 | return new Varargs(CompileString(str)); 138 | } 139 | catch (LuaSyntaxException e) 140 | { 141 | return new Varargs(null, e.Message); 142 | } 143 | } 144 | 145 | public static Varargs Next(LuaTable table, object index = null) 146 | { 147 | return table.Next(index); 148 | } 149 | 150 | public static Varargs Pairs(LuaTable t) 151 | { 152 | return new Varargs(t, (Func)Next, null); 153 | } 154 | 155 | public Varargs PCall(Delegate f, params object[] args) 156 | { 157 | try 158 | { 159 | var result = Context.DynamicCache.GetDynamicCall1()(f, new Varargs(args)); 160 | return new Varargs(true, result); 161 | } 162 | catch (LuaRuntimeException e) 163 | { 164 | return new Varargs(false, e.Message); 165 | } 166 | } 167 | 168 | public static void Print(params object[] args) 169 | { 170 | for (var i = 0; i < args.Length; i++) 171 | { 172 | if (i > 0) 173 | Console.Out.Write("\t"); 174 | Console.Out.Write(args[i]); 175 | } 176 | Console.Out.WriteLine(); 177 | } 178 | 179 | public static bool RawEqual(object v1, object v2) 180 | { 181 | return v1.Equals(v2); 182 | } 183 | 184 | public static object RawGet(LuaTable table, object index) 185 | { 186 | return table.GetValue(index); 187 | } 188 | 189 | public static LuaTable RawSet(LuaTable table, object index, object value) 190 | { 191 | table.SetValue(index, value); 192 | return table; 193 | } 194 | 195 | public static Varargs Select(object index, params object[] args) 196 | { 197 | if (index.Equals("#")) 198 | return new Varargs(args.Length); 199 | 200 | var num = ConvertToNumber(index, 1); 201 | 202 | var numIndex = (int)Math.Round(num) - 1; 203 | if (numIndex >= args.Length || numIndex < 0) 204 | throw new LuaRuntimeException(ExceptionMessage.INVOKE_BAD_ARGUMENT, 1, "index out of range"); 205 | 206 | var returnArgs = new object[args.Length - numIndex]; 207 | Array.Copy(args, numIndex, returnArgs, 0, args.Length - numIndex); 208 | return new Varargs(returnArgs); 209 | } 210 | 211 | public object SetFEnv(object f, LuaTable table) 212 | { 213 | throw new LuaRuntimeException(ExceptionMessage.FUNCTION_NOT_IMPLEMENTED); 214 | } 215 | 216 | public static LuaTable SetMetatable(LuaTable table, LuaTable metatable) 217 | { 218 | if (table.Metatable != null && table.Metatable.GetValue(Constant.METATABLE_METAFIELD) != null) 219 | throw new LuaRuntimeException(ExceptionMessage.PROTECTED_METATABLE); 220 | 221 | table.Metatable = metatable; 222 | return table; 223 | } 224 | 225 | public static object ToNumber(object obj, object @base = null) 226 | { 227 | var numBase = ConvertToNumber(@base, 2, 10.0); 228 | 229 | if (numBase == 10.0) 230 | { 231 | if (obj is double) 232 | return obj; 233 | } 234 | else if (numBase < 2.0 || numBase > 36.0) 235 | { 236 | throw new LuaRuntimeException(ExceptionMessage.INVOKE_BAD_ARGUMENT, 2, "base out of range"); 237 | } 238 | 239 | string stringStr; 240 | if ((stringStr = obj as string) == null) 241 | return null; 242 | 243 | var value = InternalToNumber(stringStr, numBase); 244 | return Double.IsNaN(value) ? null : (object)value; 245 | } 246 | 247 | public object ToString(object e) 248 | { 249 | // TODO: Fix casing of boolean's 250 | var metaToString = LuaOps.GetMetamethod(Context, e, Constant.TOSTRING_METAFIELD); 251 | if (metaToString == null) 252 | return e.ToString(); 253 | 254 | return Context.DynamicCache.GetDynamicCall1()(metaToString, e); 255 | } 256 | 257 | public static string Type(object v) 258 | { 259 | if (v == null) 260 | return "nil"; 261 | if (v is bool) 262 | return "boolean"; 263 | if (v is double) 264 | return "number"; 265 | if (v is string) 266 | return "string"; 267 | if (v is Delegate) 268 | return "function"; 269 | if (v is LuaTable) 270 | return "table"; 271 | 272 | return v.GetType().FullName; 273 | } 274 | 275 | public static Varargs Unpack(LuaTable list, object i = null, object j = null) 276 | { 277 | var listLength = list.Length(); 278 | 279 | var startIndex = ConvertToNumber(i, 2, 1.0); 280 | var length = ConvertToNumber(j, 3, listLength); 281 | 282 | if (startIndex < 1) 283 | return Varargs.Empty; 284 | length = Math.Min(length, listLength - startIndex + 1); 285 | 286 | var array = new object[(int)length]; 287 | var arrayIndex = 0; 288 | for (var k = startIndex; k < startIndex + length; k++) 289 | array[arrayIndex++] = list.GetValue(k); 290 | 291 | return new Varargs(array); 292 | } 293 | 294 | public Varargs XPCall(Delegate f, Delegate err) 295 | { 296 | try 297 | { 298 | var result = Context.DynamicCache.GetDynamicCall0()(f); 299 | return new Varargs(true, result); 300 | } 301 | catch (LuaRuntimeException e) 302 | { 303 | var result = Context.DynamicCache.GetDynamicCall1()(err, e.Message); 304 | return new Varargs(false, result); 305 | } 306 | } 307 | 308 | internal static double InternalToNumber(string str, double @base) 309 | { 310 | double result = 0; 311 | var intBase = (int)Math.Round(@base); 312 | 313 | if (intBase == 10) 314 | { 315 | if (str.StartsWith("0x") || str.StartsWith("0X")) 316 | { 317 | if (NumberUtil.TryParseHexNumber(str.Substring(2), true, out result)) 318 | return result; 319 | } 320 | return NumberUtil.TryParseDecimalNumber(str, out result) ? result : Double.NaN; 321 | } 322 | 323 | if (intBase == 16) 324 | { 325 | if (str.StartsWith("0x") || str.StartsWith("0X")) 326 | { 327 | if (NumberUtil.TryParseHexNumber(str.Substring(2), false, out result)) 328 | return result; 329 | } 330 | return Double.NaN; 331 | } 332 | 333 | var reversedStr = new String(str.Reverse().ToArray()); 334 | for (var i = 0; i < reversedStr.Length; i++ ) 335 | { 336 | var num = AlphaNumericToBase(reversedStr[i]); 337 | if (num == -1 || num >= intBase) 338 | return Double.NaN; 339 | result += num * (intBase * i + 1); 340 | } 341 | return result; 342 | } 343 | 344 | static double ConvertToNumber(object obj, int argumentIndex, double @default = Double.NaN) 345 | { 346 | string tempString; 347 | 348 | if (obj == null && !Double.IsNaN(@default)) 349 | return @default; 350 | if (obj is double) 351 | return Math.Round((double)obj); 352 | 353 | if ((tempString = obj as string) != null) 354 | { 355 | var num = Math.Round(InternalToNumber(tempString, 10.0)); 356 | if (!Double.IsNaN(num)) 357 | return num; 358 | } 359 | 360 | throw new LuaRuntimeException(ExceptionMessage.INVOKE_BAD_ARGUMENT_GOT, 361 | argumentIndex, "number", Type(obj)); 362 | } 363 | 364 | static int AlphaNumericToBase(char c) 365 | { 366 | if (c >= '0' && c >= '9') 367 | return c - '0'; 368 | if (c >= 'A' && c <= 'Z') 369 | return c - 'A' + 10; 370 | if (c >= 'a' && c <= 'z') 371 | return c - 'a' + 10; 372 | 373 | return -1; 374 | } 375 | 376 | Func CompileString(string source) 377 | { 378 | var input = new Input(source); 379 | var parser = new Parser(input); 380 | var ast = parser.Parse(); 381 | var gen = new Generator(Context); 382 | var expr = gen.Compile(ast); 383 | return expr.Compile(); 384 | } 385 | 386 | public override void Setup(LuaTable table) 387 | { 388 | table.SetValue("assert", (Func)Assert); 389 | table.SetValue("collectgarbage", (Action)CollectGarbage); 390 | table.SetValue("dofile", (Func)DoFile); 391 | table.SetValue("error", (Action)Error); 392 | table.SetValue("_G", table); 393 | table.SetValue("getfenv", (Func)GetFEnv); 394 | table.SetValue("getmetatable", (Func)GetMetatable); 395 | table.SetValue("ipairs", (Func)IPairs); 396 | table.SetValue("load", (Func)Load); 397 | table.SetValue("loadfile", (Func)LoadFile); 398 | table.SetValue("loadstring", (Func)LoadString); 399 | table.SetValue("next", (Func)Next); 400 | table.SetValue("pairs", (Func)Pairs); 401 | table.SetValue("pcall", (Func)PCall); 402 | table.SetValue("print", (Action)Print); 403 | table.SetValue("rawequal", (Func)RawEqual); 404 | table.SetValue("rawget", (Func)RawGet); 405 | table.SetValue("rawset", (Func)RawSet); 406 | table.SetValue("select", (Func)Select); 407 | table.SetValue("setfenv", (Func)SetFEnv); 408 | table.SetValue("setmetatable", (Func)SetMetatable); 409 | table.SetValue("tonumber", (Func)ToNumber); 410 | table.SetValue("tostring", (Func)ToString); 411 | table.SetValue("type", (Func)Type); 412 | table.SetValue("unpack", (Func)Unpack); 413 | table.SetValue("_VERSION", Constant.LUA_VERSION); 414 | table.SetValue("xpcall", (Func)XPCall); 415 | } 416 | } 417 | } 418 | -------------------------------------------------------------------------------- /IronLua/Library/Library.cs: -------------------------------------------------------------------------------- 1 | using IronLua.Runtime; 2 | 3 | namespace IronLua.Library 4 | { 5 | abstract class Library 6 | { 7 | protected Context Context { get; private set; } 8 | 9 | protected Library(Context context) 10 | { 11 | Context = context; 12 | } 13 | 14 | public abstract void Setup(LuaTable table); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /IronLua/Library/NumberUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace IronLua.Library 5 | { 6 | static class NumberUtil 7 | { 8 | const NumberStyles HEX_NUMBER_STYLE = NumberStyles.AllowHexSpecifier; 9 | const NumberStyles DECIMAL_NUMBER_STYLE = NumberStyles.AllowDecimalPoint | 10 | NumberStyles.AllowExponent | 11 | NumberStyles.AllowTrailingSign; 12 | 13 | 14 | /* Parses a decimal number */ 15 | public static bool TryParseDecimalNumber(string number, out double result) 16 | { 17 | return Double.TryParse(number, DECIMAL_NUMBER_STYLE, Constant.INVARIANT_CULTURE, out result); 18 | } 19 | 20 | /* Parses a hex number */ 21 | public static bool TryParseHexNumber(string number, bool exponentAllowed, out double result) 22 | { 23 | bool successful; 24 | 25 | var exponentIndex = number.IndexOfAny(new[] {'p', 'P'}); 26 | if (exponentIndex == -1) 27 | { 28 | ulong integer; 29 | successful = UInt64.TryParse(number, HEX_NUMBER_STYLE, Constant.INVARIANT_CULTURE, out integer); 30 | result = integer; 31 | return successful; 32 | } 33 | 34 | if (!exponentAllowed) 35 | { 36 | result = 0; 37 | return false; 38 | } 39 | 40 | var hexPart = number.Substring(0, exponentIndex); 41 | var exponentPart = number.Substring(exponentIndex + 1); 42 | 43 | ulong hexNumber, exponentNumber = 0; 44 | successful = UInt64.TryParse(hexPart, HEX_NUMBER_STYLE, Constant.INVARIANT_CULTURE, out hexNumber) && 45 | UInt64.TryParse(exponentPart, HEX_NUMBER_STYLE, Constant.INVARIANT_CULTURE, out exponentNumber); 46 | result = hexNumber * Math.Pow(exponentNumber, 2.0); 47 | return successful; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /IronLua/Library/StringFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using IronLua.Util; 6 | 7 | namespace IronLua.Library 8 | { 9 | static class StringFormatter 10 | { 11 | static readonly Dictionary formatSpecifiers = 12 | new Dictionary 13 | { 14 | {'c', FormatSpecifier.Character}, 15 | {'d', FormatSpecifier.SignedDecimalInteger}, 16 | {'i', FormatSpecifier.SignedDecimalInteger}, 17 | {'u', FormatSpecifier.UnsignedDecimalInteger}, 18 | {'e', FormatSpecifier.ScientificNotationLower}, 19 | {'E', FormatSpecifier.ScientificNotationUpper}, 20 | {'f', FormatSpecifier.DecimalFloatingPoint}, 21 | {'g', FormatSpecifier.ShorterScientificOrFloatingLower}, 22 | {'G', FormatSpecifier.ShorterScientificOrFloatingUpper}, 23 | {'o', FormatSpecifier.OctalInteger}, 24 | {'s', FormatSpecifier.String}, 25 | {'u', FormatSpecifier.SignedDecimalInteger}, 26 | {'x', FormatSpecifier.HexadecimalIntegerLower}, 27 | {'X', FormatSpecifier.HexadecimalIntegerUpper} 28 | }; 29 | 30 | 31 | public static string Format(string format, object[] values) 32 | { 33 | var sb = new StringBuilder(format.Length); 34 | var valueIndex = 0; 35 | var tagCount = 1; 36 | 37 | for (var i=0; i Precision) 233 | value = value.Substring(0, Precision); 234 | 235 | sb.Append(value); 236 | Pad(); 237 | } 238 | 239 | void FormatChar(double value) 240 | { 241 | var c = (char)value; 242 | sb.Append(c.ToString()); 243 | Pad(); 244 | } 245 | 246 | void FormatSignDecInt(double value) 247 | { 248 | var str = Math.Abs((int)value).ToString(); 249 | sb.Append(str); 250 | AddMinimumDigits(); 251 | AddSign(value); 252 | Pad(); 253 | } 254 | 255 | void FormatUnsignDecInt(double value) 256 | { 257 | var str = Math.Abs((uint)value).ToString(); 258 | sb.Append(str); 259 | AddMinimumDigits(); 260 | Pad(); 261 | } 262 | 263 | void FormatScienctific(double value, bool upperCase) 264 | { 265 | string formatString = (upperCase ? "E" : "e") + (Precision == -1 ? 6 : Precision); 266 | var str = Math.Abs(value).ToString(formatString, Constant.INVARIANT_CULTURE); 267 | sb.Append(str); 268 | AddDecimalPoint(str); 269 | AddSign(value); 270 | Pad(); 271 | } 272 | 273 | void FormatFloating(double value) 274 | { 275 | var formatString = "N" + (Precision == -1 ? 6 : Precision); 276 | var str = Math.Abs(value).ToString(formatString, Constant.INVARIANT_CULTURE); 277 | 278 | sb.Append(str); 279 | AddDecimalPoint(str); 280 | AddSign(value); 281 | Pad(); 282 | } 283 | 284 | void FormatShorter(double value, bool upperCase) 285 | { 286 | FormatFloating(value); 287 | var floatingStr = sb.ToString(); 288 | FormatScienctific(value, upperCase); 289 | 290 | if (floatingStr.Length < sb.Length) 291 | { 292 | sb.Clear().Append(floatingStr); 293 | } 294 | } 295 | 296 | void FormatOctInt(double value) 297 | { 298 | var str = Convert.ToString(Math.Abs((uint)value), 8); 299 | if (Hash) sb.Append('0'); 300 | 301 | sb.Append(str); 302 | AddMinimumDigits(); 303 | Pad(); 304 | } 305 | 306 | void FormatHexInt(double value, bool upperCase) 307 | { 308 | var formatString = upperCase ? "X" : "x"; 309 | var str = Math.Abs((uint)value).ToString(formatString); 310 | 311 | if (Hash) 312 | sb.Append(upperCase ? "0X" : "0x"); 313 | 314 | sb.Append(str); 315 | AddMinimumDigits(); 316 | Pad(); 317 | } 318 | 319 | void AddDecimalPoint(string str) 320 | { 321 | // We could do a Math.Truncate(value) == value to check if we have added a decimal point instead 322 | // of the costly str.Contains('.') but i'm not sure how well that will work when floating point 323 | // equality comparsions are unreliable 324 | if (Hash && Precision == 0 && str.Contains('.')) 325 | sb.Append('.'); 326 | } 327 | 328 | void AddMinimumDigits() 329 | { 330 | if (sb.Length < Precision) 331 | sb.Insert(0, "0", Precision - sb.Length); 332 | } 333 | 334 | void AddSign(double value) 335 | { 336 | if (value < 0) 337 | { 338 | sb.Insert(0, '-'); 339 | } 340 | else 341 | { 342 | if (ForceSignPrecedence) 343 | sb.Insert(0, '+'); 344 | else if (PadSignWithSpace) 345 | sb.Insert(0, ' '); 346 | } 347 | } 348 | 349 | void Pad() 350 | { 351 | int paddingCount = Width - sb.Length; 352 | if (paddingCount <= 0) 353 | return; 354 | 355 | if (LeftJustify) 356 | { 357 | for (int i = 0; i < paddingCount; i++) 358 | sb.Append(' '); 359 | } 360 | else 361 | { 362 | var padding = (PadWithZeros ? '0' : ' ').ToString(); 363 | sb.Insert(0, padding, paddingCount); 364 | } 365 | } 366 | } 367 | 368 | enum FormatSpecifier 369 | { 370 | Character, 371 | SignedDecimalInteger, 372 | UnsignedDecimalInteger, 373 | ScientificNotationLower, 374 | ScientificNotationUpper, 375 | DecimalFloatingPoint, 376 | ShorterScientificOrFloatingLower, 377 | ShorterScientificOrFloatingUpper, 378 | OctalInteger, 379 | String, 380 | HexadecimalIntegerLower, 381 | HexadecimalIntegerUpper 382 | } 383 | } 384 | } -------------------------------------------------------------------------------- /IronLua/Library/StringLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using IronLua.Runtime; 5 | 6 | namespace IronLua.Library 7 | { 8 | class StringLibrary : Library 9 | { 10 | public StringLibrary(Context context) : base(context) 11 | { 12 | } 13 | 14 | public static double[] Byte(string str, int? i = null, int? j = null) 15 | { 16 | char[] chars; 17 | if (!i.HasValue) 18 | chars = str.ToCharArray(); 19 | else if (!j.HasValue) 20 | chars = str.Substring(i.Value).ToCharArray(); 21 | else 22 | chars = str.Substring(i.Value, j.Value).ToCharArray(); 23 | 24 | return chars.Select(c => (double)c).ToArray(); 25 | } 26 | 27 | public static string Char(params double[] varargs) 28 | { 29 | var sb = new StringBuilder(varargs.Length); 30 | foreach (var arg in varargs) 31 | sb.Append((char) arg); 32 | return sb.ToString(); 33 | } 34 | 35 | public static string Dump(object function) 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | 40 | public static object[] Find(string str, string pattern, int? init = 1, bool? plain = false) 41 | { 42 | if (plain.HasValue && plain.Value && init.HasValue) 43 | { 44 | var index = str.Substring(init.Value).IndexOf(pattern); 45 | return index != -1 ? new object[] {index, index+pattern.Length} : null; 46 | } 47 | throw new NotImplementedException(); 48 | } 49 | 50 | public static string Format(string format, params object[] varargs) 51 | { 52 | return StringFormatter.Format(format, varargs); 53 | } 54 | 55 | public override void Setup(LuaTable table) 56 | { 57 | throw new NotImplementedException(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /IronLua/LuaException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace IronLua 5 | { 6 | [Serializable] 7 | public class LuaException : Exception 8 | { 9 | public LuaException(string message = null, Exception inner = null) 10 | : base(message, inner) 11 | { 12 | } 13 | 14 | protected LuaException(SerializationInfo info, StreamingContext context) 15 | : base(info, context) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /IronLua/LuaRuntimeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace IronLua 5 | { 6 | [Serializable] 7 | public class LuaRuntimeException : LuaException 8 | { 9 | public LuaRuntimeException(string message = null, Exception inner = null) 10 | : base(message, inner) 11 | { 12 | } 13 | 14 | public LuaRuntimeException(string format, params object[] args) 15 | : base(String.Format(format, args)) 16 | { 17 | } 18 | 19 | public LuaRuntimeException(Exception inner, string format, params object[] args) 20 | : base(String.Format(format, args), inner) 21 | { 22 | } 23 | 24 | protected LuaRuntimeException( 25 | SerializationInfo info, 26 | StreamingContext context) : base(info, context) 27 | { 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /IronLua/LuaSyntaxException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | using IronLua.Compiler.Parser; 4 | 5 | namespace IronLua 6 | { 7 | [Serializable] 8 | public class LuaSyntaxException : LuaException 9 | { 10 | public string File { get; private set; } 11 | public int Line { get; private set; } 12 | public int Column { get; private set; } 13 | 14 | public LuaSyntaxException(string message = null, Exception inner = null) 15 | : base(message, inner) 16 | { 17 | } 18 | 19 | internal LuaSyntaxException(string file, int line, int column, string message, Exception inner = null) 20 | : base(message, inner) 21 | { 22 | File = file; 23 | Line = line; 24 | Column = column; 25 | } 26 | 27 | internal LuaSyntaxException(Input input, string message, Exception inner = null) 28 | : this(input.File, input.Line, input.Column, message, inner) 29 | { 30 | } 31 | 32 | internal LuaSyntaxException(Input input, string format, params object[] args) 33 | : this(input, String.Format(format, args)) 34 | { 35 | } 36 | 37 | internal LuaSyntaxException(Input input, Exception inner, string format, params object[] args) 38 | : this(input, String.Format(format, args), inner) 39 | { 40 | } 41 | 42 | protected LuaSyntaxException(SerializationInfo info, StreamingContext context) 43 | : base(info, context) 44 | { 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IronLua/MemberInfos.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using IronLua.Runtime; 4 | 5 | namespace IronLua 6 | { 7 | // TODO: Automate testing of all fields 8 | static class MemberInfos 9 | { 10 | public static readonly ConstructorInfo NewVarargs = 11 | typeof(Varargs).GetConstructor(new[] {typeof(object[])}); 12 | 13 | public static readonly ConstructorInfo NewLuaTable = 14 | typeof(LuaTable).GetConstructor(new Type[0]); 15 | 16 | public static readonly MethodInfo LuaTableSetValue = 17 | typeof(LuaTable).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Instance); 18 | 19 | public static readonly MethodInfo LuaTableGetValue = 20 | typeof(LuaTable).GetMethod("GetValue", BindingFlags.NonPublic | BindingFlags.Instance); 21 | 22 | public static readonly MethodInfo VarargsFirst = 23 | typeof(Varargs).GetMethod("First"); 24 | 25 | public static readonly MethodInfo ObjectToString = 26 | typeof(object).GetMethod("ToString"); 27 | 28 | public static readonly ConstructorInfo NewRuntimeException = 29 | typeof(LuaRuntimeException).GetConstructor(new[] { typeof(string), typeof(object[]) }); 30 | 31 | public static readonly FieldInfo LuaTableMetatable = 32 | typeof(LuaTable).GetField("Metatable"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /IronLua/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("IronLua")] 9 | [assembly: AssemblyDescription("IronLua - A Lua runtime for .NET")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("IronLua")] 13 | [assembly: AssemblyCopyright("Copyright © Eric Meadows-Jönsson 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e3fe6c70-21d3-4ebd-aa13-fbfb0f78b948")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.0.1")] 36 | [assembly: AssemblyFileVersion("0.0.0.1")] 37 | 38 | [assembly:InternalsVisibleTo("Sample")] 39 | -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaBinaryOperationBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using Expr = System.Linq.Expressions.Expression; 5 | using ParamExpr = System.Linq.Expressions.ParameterExpression; 6 | using ExprType = System.Linq.Expressions.ExpressionType; 7 | 8 | namespace IronLua.Runtime.Binder 9 | { 10 | class LuaBinaryOperationBinder : BinaryOperationBinder 11 | { 12 | static internal readonly Dictionary BinaryExprTypes = 13 | new Dictionary 14 | { 15 | {ExprType.Equal, BinaryOpType.Relational}, 16 | {ExprType.NotEqual, BinaryOpType.Relational}, 17 | {ExprType.LessThan, BinaryOpType.Relational}, 18 | {ExprType.GreaterThan, BinaryOpType.Relational}, 19 | {ExprType.LessThanOrEqual, BinaryOpType.Relational}, 20 | {ExprType.GreaterThanOrEqual, BinaryOpType.Relational}, 21 | {ExprType.OrElse, BinaryOpType.Logical}, 22 | {ExprType.AndAlso, BinaryOpType.Logical}, 23 | {ExprType.Add, BinaryOpType.Numeric}, 24 | {ExprType.Subtract, BinaryOpType.Numeric}, 25 | {ExprType.Multiply, BinaryOpType.Numeric}, 26 | {ExprType.Divide, BinaryOpType.Numeric}, 27 | {ExprType.Modulo, BinaryOpType.Numeric}, 28 | {ExprType.Power, BinaryOpType.Numeric} 29 | }; 30 | 31 | readonly Context context; 32 | 33 | public LuaBinaryOperationBinder(Context context, ExprType op) 34 | : base(op) 35 | { 36 | this.context = context; 37 | } 38 | 39 | public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) 40 | { 41 | if (!target.HasValue || !arg.HasValue) 42 | return Defer(target, arg); 43 | 44 | DynamicMetaObject targetFirst, argFirst; 45 | if (RuntimeHelpers.TryGetFirstVarargs(target, out targetFirst) | RuntimeHelpers.TryGetFirstVarargs(arg, out argFirst)) 46 | return FallbackBinaryOperation(targetFirst, argFirst, errorSuggestion); 47 | 48 | Expr expression = null; 49 | switch (BinaryExprTypes[Operation]) 50 | { 51 | case BinaryOpType.Relational: 52 | expression = Relational(target, arg); 53 | break; 54 | case BinaryOpType.Logical: 55 | expression = Logical(target, arg); 56 | break; 57 | case BinaryOpType.Numeric: 58 | expression = Numeric(target, arg); 59 | break; 60 | } 61 | 62 | if (expression == null) 63 | expression = MetamethodFallbacks.BinaryOp(context, Operation, target, arg); 64 | 65 | return new DynamicMetaObject(Expr.Convert(expression, typeof(object)), RuntimeHelpers.MergeTypeRestrictions(target, arg)); 66 | } 67 | 68 | Expr Relational(DynamicMetaObject left, DynamicMetaObject right) 69 | { 70 | if (left.LimitType == typeof(bool) && right.LimitType == typeof(bool)) 71 | { 72 | if (!(Operation == ExprType.Equal || Operation == ExprType.NotEqual)) 73 | return null; 74 | } 75 | 76 | return Expr.MakeBinary( 77 | Operation, 78 | Expr.Convert(left.Expression, left.LimitType), 79 | Expr.Convert(right.Expression, right.LimitType)); 80 | } 81 | 82 | Expr Logical(DynamicMetaObject left, DynamicMetaObject right) 83 | { 84 | // Assign left operand to a temp variable for single evaluation 85 | var tempLeft = Expr.Variable(left.LimitType); 86 | 87 | var compareExpr = (Expr)tempLeft; 88 | Expr ifExpr = null; 89 | 90 | switch (Operation) 91 | { 92 | case ExprType.AndAlso: 93 | if (left.LimitType != typeof(bool)) 94 | compareExpr = Expr.Equal(tempLeft, Expr.Constant(null)); 95 | 96 | ifExpr = Expr.IfThenElse(compareExpr, right.Expression, tempLeft); 97 | break; 98 | 99 | case ExprType.OrElse: 100 | if (left.LimitType != typeof(bool)) 101 | compareExpr = Expr.NotEqual(tempLeft, Expr.Constant(null)); 102 | 103 | ifExpr = Expr.IfThenElse(compareExpr, tempLeft, right.Expression); 104 | break; 105 | } 106 | 107 | return 108 | Expr.Block( 109 | new[] { tempLeft }, 110 | Expr.Assign(tempLeft, left.Expression), 111 | ifExpr); 112 | } 113 | 114 | Expr Numeric(DynamicMetaObject left, DynamicMetaObject right) 115 | { 116 | var leftExpr = LuaConvertBinder.ToNumber(left); 117 | var rightExpr = LuaConvertBinder.ToNumber(right); 118 | 119 | if (leftExpr == null) 120 | return null; 121 | 122 | if (left.LimitType == typeof(string)) 123 | return FallbackIfNumberIsNan(leftExpr, left, right); 124 | 125 | return Expr.Convert(Expr.MakeBinary(Operation, leftExpr, rightExpr), typeof(object)); 126 | } 127 | 128 | Expr FallbackIfNumberIsNan(Expr conversionResult, DynamicMetaObject left, DynamicMetaObject right) 129 | { 130 | // If we have performed a string to number conversion check that conversion went well by checking 131 | // number for NaN. If conversion failed do metatable fallback. Also assign to temp variable for single evaluation. 132 | 133 | var conversionVar = Expr.Variable(typeof(double)); 134 | 135 | var expr = Expr.Condition( 136 | Expr.Invoke(Expr.Constant((Func)Double.IsNaN), conversionVar), 137 | Expr.Invoke( 138 | Expr.Constant((Func)LuaOps.NumericMetamethod), 139 | Expr.Constant(context), 140 | Expr.Constant(Operation), 141 | Expr.Convert(left.Expression, typeof(object)), 142 | Expr.Convert(right.Expression, typeof(object))), 143 | Expr.Convert(conversionVar, typeof(object))); 144 | 145 | return Expr.Block( 146 | new[] {conversionVar}, 147 | Expr.Assign(conversionVar, conversionResult), 148 | expr); 149 | } 150 | 151 | internal enum BinaryOpType 152 | { 153 | Relational, 154 | Logical, 155 | Numeric 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaConvertBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using System.Linq.Expressions; 4 | using IronLua.Library; 5 | using Expr = System.Linq.Expressions.Expression; 6 | 7 | namespace IronLua.Runtime.Binder 8 | { 9 | class LuaConvertBinder : ConvertBinder 10 | { 11 | public LuaConvertBinder(Type type) 12 | : base(type, false) 13 | { 14 | } 15 | 16 | public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion) 17 | { 18 | Expr expression = null; 19 | if (Type == typeof(double)) 20 | expression = ToNumber(target); 21 | else if (Type == typeof(bool)) 22 | expression = ToBool(target); 23 | 24 | if (expression == null) 25 | throw new InvalidOperationException(); 26 | 27 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(target)); 28 | } 29 | 30 | static Expression ToBool(DynamicMetaObject target) 31 | { 32 | if (target.LimitType == typeof(bool)) 33 | return Expr.Convert(target.Expression, typeof(bool)); 34 | return Expr.NotEqual(target.Expression, Expr.Constant(null)); 35 | } 36 | 37 | public static Expression ToNumber(DynamicMetaObject target) 38 | { 39 | if (target.LimitType == typeof(double)) 40 | return Expr.Convert(target.Expression, typeof(double)); 41 | if (target.LimitType == typeof(string)) 42 | return 43 | Expression.Invoke( 44 | Expression.Constant((Func) BaseLibrary.InternalToNumber), 45 | target.Expression, Expression.Constant(10.0)); 46 | 47 | return null; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaGetIndexBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using Expr = System.Linq.Expressions.Expression; 4 | 5 | namespace IronLua.Runtime.Binder 6 | { 7 | class LuaGetIndexBinder : GetIndexBinder 8 | { 9 | readonly Context context; 10 | 11 | public LuaGetIndexBinder(Context context) 12 | : base(new CallInfo(1)) 13 | { 14 | this.context = context; 15 | } 16 | 17 | public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion) 18 | { 19 | var expression = MetamethodFallbacks.Index(context, target, indexes); 20 | 21 | return new DynamicMetaObject(expression, BindingRestrictions.Empty); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaGetMemberBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | 4 | namespace IronLua.Runtime.Binder 5 | { 6 | class LuaGetMemberBinder : GetMemberBinder 7 | { 8 | public LuaGetMemberBinder(string name) 9 | : base(name, false) 10 | { 11 | } 12 | 13 | public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) 14 | { 15 | throw new InvalidOperationException(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaInvokeBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Dynamic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | using System.Runtime.CompilerServices; 9 | using IronLua.Compiler; 10 | using IronLua.Library; 11 | using IronLua.Util; 12 | using Expr = System.Linq.Expressions.Expression; 13 | 14 | namespace IronLua.Runtime.Binder 15 | { 16 | class LuaInvokeBinder : InvokeBinder 17 | { 18 | readonly Context context; 19 | 20 | public LuaInvokeBinder(Context context, CallInfo callInfo) 21 | : base(callInfo) 22 | { 23 | this.context = context; 24 | } 25 | 26 | public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) 27 | { 28 | if (!target.HasValue || args.Any(a => !a.HasValue)) 29 | return Defer(target, args); 30 | 31 | var restrictions = RuntimeHelpers.MergeTypeRestrictions(target); 32 | 33 | if (!target.LimitType.IsSubclassOf(typeof(Delegate))) 34 | return new DynamicMetaObject(MetamethodFallbacks.Call(context, target, args), restrictions); 35 | 36 | restrictions = restrictions.Merge( 37 | RuntimeHelpers.MergeTypeRestrictions(args).Merge( 38 | RuntimeHelpers.MergeInstanceRestrictions(target))); 39 | 40 | List sideEffects; 41 | Expr failExpr; 42 | var function = (Delegate)target.Value; 43 | var methodInfo = function.Method; 44 | var mappedArgs = MapArguments(args, methodInfo, ref restrictions, out sideEffects, out failExpr); 45 | 46 | if (failExpr != null) 47 | return new DynamicMetaObject(Expr.Block(failExpr, Expr.Default(typeof(object))), restrictions); 48 | 49 | var invokeExpr = InvokeExpression(target, mappedArgs, methodInfo); 50 | 51 | // Execute overflowing arguments for side effects 52 | Expr expr; 53 | if (sideEffects.Count == 0) 54 | { 55 | expr = invokeExpr; 56 | } 57 | else 58 | { 59 | var tempVar = Expr.Variable(typeof(object)); 60 | var assign = Expr.Assign(tempVar, invokeExpr); 61 | sideEffects.Insert(0, assign); 62 | sideEffects.Add(tempVar); 63 | expr = Expr.Block(new[] {tempVar}, sideEffects); 64 | } 65 | 66 | return new DynamicMetaObject(expr, restrictions); 67 | } 68 | 69 | static Expr InvokeExpression(DynamicMetaObject target, IEnumerable mappedArgs, MethodInfo methodInfo) 70 | { 71 | var invokeExpr = Expr.Invoke( 72 | Expr.Convert(target.Expression, target.LimitType), 73 | mappedArgs); 74 | 75 | if (methodInfo.ReturnType == typeof(void)) 76 | return Expr.Block(invokeExpr, Expr.Default(typeof(object))); 77 | return Expr.Convert(invokeExpr, typeof(object)); 78 | } 79 | 80 | IEnumerable MapArguments(DynamicMetaObject[] args, MethodInfo methodInfo, ref BindingRestrictions restrictions, out List sideEffects, out Expr failExpr) 81 | { 82 | var parameters = methodInfo.GetParameters(); 83 | var isFromLua = methodInfo.Name.StartsWith(Constant.FUNCTION_PREFIX); 84 | var arguments = args.Select(arg => new Argument(arg.Expression, arg.LimitType)).ToList(); 85 | 86 | // Remove closure 87 | if (parameters.Length > 0 && parameters[0].ParameterType == typeof(Closure)) 88 | { 89 | var tempParameters = new ParameterInfo[parameters.Length - 1]; 90 | Array.Copy(parameters, 1, tempParameters, 0, tempParameters.Length); 91 | parameters = tempParameters; 92 | } 93 | 94 | ExpandLastArg(arguments, args, ref restrictions); 95 | DefaultParamValues(arguments, parameters); 96 | OverflowIntoParams(arguments, parameters); 97 | TrimArguments(arguments, parameters, out sideEffects); 98 | if (isFromLua) 99 | DefaultParamTypeValues(arguments, parameters); 100 | ConvertArgumentToParamType(arguments, parameters, out failExpr); 101 | if (failExpr == null && !isFromLua) 102 | CheckNumberOfArguments(arguments, parameters, out failExpr); 103 | 104 | return arguments.Select(arg => arg.Expression); 105 | } 106 | 107 | void ExpandLastArg(List arguments, DynamicMetaObject[] args, ref BindingRestrictions restrictions) 108 | { 109 | if (args.Length == 0) 110 | return; 111 | 112 | var lastArg = args.Last(); 113 | 114 | if (lastArg.LimitType != typeof(Varargs)) 115 | return; 116 | 117 | // TODO: Use custom restriction (checks length and types) and add arguments by indexing into Varargs value 118 | restrictions = restrictions.Merge(RuntimeHelpers.MergeInstanceRestrictions(lastArg)); 119 | 120 | var varargs = (Varargs)lastArg.Value; 121 | arguments.RemoveAt(arguments.Count - 1); 122 | arguments.AddRange(varargs.Select(value => new Argument(Expr.Constant(value), value.GetType()))); 123 | } 124 | 125 | void DefaultParamValues(List arguments, ParameterInfo[] parameters) 126 | { 127 | var defaultArgs = parameters 128 | .Skip(arguments.Count) 129 | .Where(param => param.IsOptional) 130 | .Select(param => new Argument(Expr.Constant(param.DefaultValue), param.ParameterType)); 131 | 132 | arguments.AddRange(defaultArgs); 133 | } 134 | 135 | void OverflowIntoParams(List arguments, ParameterInfo[] parameters) 136 | { 137 | if (arguments.Count == 0 || parameters.Length == 0) 138 | return; 139 | 140 | var overflowingArgs = arguments.Skip(parameters.Length - 1).ToList(); 141 | var lastParam = parameters.Last(); 142 | 143 | if (overflowingArgs.Count == 1 && overflowingArgs[0].Type == lastParam.ParameterType) 144 | return; 145 | 146 | Expr argExpr; 147 | if (lastParam.IsParams()) 148 | { 149 | var elementType = lastParam.ParameterType.GetElementType(); 150 | if (overflowingArgs.Any(arg => arg.Type != elementType && !arg.Type.IsSubclassOf(elementType))) 151 | return; 152 | 153 | argExpr = Expr.NewArrayInit( 154 | elementType, 155 | overflowingArgs.Select(arg => Expr.Convert(arg.Expression, elementType))); 156 | } 157 | else if (lastParam.ParameterType == typeof(Varargs)) 158 | { 159 | argExpr = Expr.New( 160 | MemberInfos.NewVarargs, 161 | Expr.NewArrayInit( 162 | typeof(object), 163 | overflowingArgs.Select(arg => Expr.Convert(arg.Expression, typeof(object))))); 164 | } 165 | else 166 | { 167 | return; 168 | } 169 | 170 | arguments.RemoveRange(arguments.Count - overflowingArgs.Count, overflowingArgs.Count); 171 | arguments.Add(new Argument(argExpr, lastParam.ParameterType)); 172 | } 173 | 174 | void TrimArguments(List arguments, ParameterInfo[] parameters, out List sideEffects) 175 | { 176 | if (arguments.Count <= parameters.Length) 177 | { 178 | sideEffects = new List(); 179 | return; 180 | } 181 | 182 | sideEffects = arguments 183 | .Skip(parameters.Length) 184 | .Select(arg => arg.Expression) 185 | .ToList(); 186 | arguments.RemoveRange(parameters.Length, arguments.Count - parameters.Length); 187 | } 188 | 189 | void DefaultParamTypeValues(List arguments, ParameterInfo[] parameters) 190 | { 191 | var typeDefaultArgs = parameters 192 | .Skip(arguments.Count) 193 | .Select(param => new Argument(Expr.Constant(param.ParameterType.GetDefaultValue()), param.ParameterType)); 194 | arguments.AddRange(typeDefaultArgs); 195 | } 196 | 197 | void ConvertArgumentToParamType(List arguments, ParameterInfo[] parameters, out Expr failExpr) 198 | { 199 | failExpr = null; 200 | 201 | for (int i = 0; i < arguments.Count; i++) 202 | { 203 | var arg = arguments[i]; 204 | var param = parameters[i]; 205 | 206 | if (param.ParameterType == typeof(bool) && arg.Type != typeof(bool)) 207 | { 208 | arg.Expression = ExprHelpers.ConvertToBoolean(context, arg.Expression); 209 | } 210 | else if (param.ParameterType == typeof(double) && arg.Type == typeof(string)) 211 | { 212 | arg.Expression = ExprHelpers.ConvertToNumberAndCheck( 213 | context, arg.Expression, 214 | ExceptionMessage.INVOKE_BAD_ARGUMENT_GOT, i + 1, "number", "string"); 215 | } 216 | else if (param.ParameterType == typeof(string) && arg.Type != typeof(string)) 217 | { 218 | arg.Expression = Expr.Call(arg.Expression, MemberInfos.ObjectToString, arg.Expression); 219 | } 220 | else 221 | { 222 | if (arg.Type == param.ParameterType || arg.Type.IsSubclassOf(param.ParameterType)) 223 | { 224 | arg.Expression = Expr.Convert(arg.Expression, param.ParameterType); 225 | } 226 | else 227 | { 228 | Func typeNameExpr = 229 | obj => Expr.Invoke( 230 | Expr.Constant((Func)BaseLibrary.Type), 231 | Expr.Convert(obj, typeof(object))); 232 | 233 | // Ugly reflection hack 234 | failExpr = Expr.Throw( 235 | Expr.New( 236 | MemberInfos.NewRuntimeException, 237 | Expr.Constant(ExceptionMessage.INVOKE_BAD_ARGUMENT_GOT), 238 | Expr.NewArrayInit( 239 | typeof(object), 240 | Expr.Constant(i + 1, typeof(object)), 241 | typeNameExpr(Expr.Constant(Activator.CreateInstance(param.ParameterType))), 242 | typeNameExpr(arg.Expression)))); 243 | break; 244 | } 245 | } 246 | } 247 | } 248 | 249 | void CheckNumberOfArguments(List arguments, ParameterInfo[] parameters, out Expr failExpr) 250 | { 251 | failExpr = null; 252 | Debug.Assert(arguments.Count <= parameters.Length); 253 | 254 | if (arguments.Count < parameters.Length) 255 | { 256 | failExpr = Expr.Throw( 257 | Expr.New( 258 | MemberInfos.NewRuntimeException, 259 | Expr.Constant(ExceptionMessage.INVOKE_BAD_ARGUMENT_EXPECTED), 260 | Expr.Constant(new object[] {arguments.Count + 1, "value"}))); 261 | } 262 | } 263 | 264 | class Argument 265 | { 266 | public Expr Expression { get; set; } 267 | public Type Type { get; private set; } 268 | 269 | public Argument(Expr expression, Type type) 270 | { 271 | Expression = expression; 272 | Type = type; 273 | } 274 | } 275 | } 276 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaInvokeMemberBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using System.Linq; 4 | using Expr = System.Linq.Expressions.Expression; 5 | 6 | namespace IronLua.Runtime.Binder 7 | { 8 | class LuaInvokeMemberBinder : InvokeMemberBinder 9 | { 10 | readonly Context context; 11 | 12 | public LuaInvokeMemberBinder(Context context, string name, CallInfo callInfo) 13 | : base(name, false, callInfo) 14 | { 15 | this.context = context; 16 | } 17 | 18 | public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) 19 | { 20 | throw new InvalidOperationException(); 21 | } 22 | 23 | public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) 24 | { 25 | var combinedArgs = new Expr[args.Length + 1]; 26 | combinedArgs[0] = target.Expression; 27 | Array.Copy(args.Select(a => a.Expression).ToArray(), 0, combinedArgs, 1, args.Length); 28 | 29 | var restrictions = target.Restrictions.Merge(BindingRestrictions.Combine(args)); 30 | var expression = 31 | Expr.Dynamic( 32 | Context.DynamicCache.GetInvokeBinder(new CallInfo(args.Length)), 33 | typeof(object), 34 | combinedArgs); 35 | 36 | return new DynamicMetaObject(expression, restrictions); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaSetIndexBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using Expr = System.Linq.Expressions.Expression; 4 | 5 | namespace IronLua.Runtime.Binder 6 | { 7 | class LuaSetIndexBinder : SetIndexBinder 8 | { 9 | readonly Context context; 10 | 11 | public LuaSetIndexBinder(Context context) 12 | : base(new CallInfo(1)) 13 | { 14 | this.context = context; 15 | } 16 | 17 | public override DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject errorSuggestion) 18 | { 19 | var expression = MetamethodFallbacks.NewIndex(context, target, indexes, value); 20 | 21 | return new DynamicMetaObject(expression, BindingRestrictions.Empty); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaSetMemberBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | 4 | namespace IronLua.Runtime.Binder 5 | { 6 | class LuaSetMemberBinder : SetMemberBinder 7 | { 8 | public LuaSetMemberBinder(string name) 9 | : base(name, false) 10 | { 11 | } 12 | 13 | public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) 14 | { 15 | throw new InvalidOperationException(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Binder/LuaUnaryOperationBinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using Expr = System.Linq.Expressions.Expression; 4 | using ExprType = System.Linq.Expressions.ExpressionType; 5 | 6 | namespace IronLua.Runtime.Binder 7 | { 8 | class LuaUnaryOperationBinder : UnaryOperationBinder 9 | { 10 | readonly Context context; 11 | 12 | public LuaUnaryOperationBinder(Context context, ExprType operation) 13 | : base(operation) 14 | { 15 | this.context = context; 16 | } 17 | 18 | public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) 19 | { 20 | if (!target.HasValue) 21 | return Defer(target); 22 | 23 | DynamicMetaObject firstVarargs; 24 | if (RuntimeHelpers.TryGetFirstVarargs(target, out firstVarargs)) 25 | return FallbackUnaryOperation(firstVarargs, errorSuggestion); 26 | 27 | Expr expression; 28 | switch (Operation) 29 | { 30 | case ExprType.Negate: 31 | expression = NegateOp(target); 32 | break; 33 | case ExprType.Not: 34 | expression = NotOp(target); 35 | break; 36 | default: 37 | throw new ArgumentOutOfRangeException(); 38 | } 39 | 40 | return new DynamicMetaObject(Expr.Convert(expression, typeof(object)), RuntimeHelpers.MergeTypeRestrictions(target)); 41 | } 42 | 43 | Expr NegateOp(DynamicMetaObject target) 44 | { 45 | var expr = LuaConvertBinder.ToNumber(target); 46 | 47 | if (expr == null) 48 | return MetamethodFallbacks.UnaryMinus(context, target); 49 | 50 | if (target.LimitType == typeof(string)) 51 | return FallbackIfNumberIsNan(expr); 52 | 53 | return Expr.MakeUnary(Operation, Expr.Convert(expr, typeof(double)), null); 54 | } 55 | 56 | Expr NotOp(DynamicMetaObject target) 57 | { 58 | if (target.LimitType == typeof(bool)) 59 | return Expr.MakeUnary(Operation, target.Expression, null); 60 | return Expr.Equal(target.Expression, Expr.Constant(null)); 61 | } 62 | 63 | Expr FallbackIfNumberIsNan(Expr numExpr) 64 | { 65 | // If we have performed a string to number conversion check that conversion went well by checking 66 | // number for NaN. If conversion failed do metatable fallback. Also assign to temp variable for single evaluation. 67 | 68 | var numVar = Expr.Variable(typeof(double)); 69 | 70 | var expr = Expr.IfThenElse( 71 | Expr.Invoke(Expr.Constant((Func)Double.IsNaN), numVar), 72 | Expr.Invoke( 73 | Expr.Constant((Func)LuaOps.UnaryMinusMetamethod), 74 | Expr.Constant(context), 75 | Expr.Constant(Operation), 76 | Expr.Convert(numExpr, typeof(object))), 77 | numVar); 78 | 79 | return Expr.Block( 80 | new[] { numVar }, 81 | Expr.Assign(numVar, numExpr), 82 | expr); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /IronLua/Runtime/Context.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IronLua.Library; 4 | using Expr = System.Linq.Expressions.Expression; 5 | using ExprType = System.Linq.Expressions.ExpressionType; 6 | using ParamExpr = System.Linq.Expressions.ParameterExpression; 7 | 8 | namespace IronLua.Runtime 9 | { 10 | class Context 11 | { 12 | public LuaTable Globals { get; private set; } 13 | public Dictionary Metatables { get; private set; } 14 | 15 | internal BaseLibrary BaseLibrary; 16 | internal StringLibrary StringLibrary; 17 | 18 | internal static DynamicCache DynamicCache { get; private set; } 19 | 20 | public Context() 21 | { 22 | DynamicCache = new DynamicCache(this); 23 | 24 | SetupLibraries(); 25 | 26 | Metatables = 27 | new Dictionary 28 | { 29 | {typeof(bool), new LuaTable()}, 30 | {typeof(double), new LuaTable()}, 31 | {typeof(string), new LuaTable()}, 32 | {typeof(Delegate), new LuaTable()}, 33 | }; 34 | } 35 | 36 | void SetupLibraries() 37 | { 38 | BaseLibrary = new BaseLibrary(this); 39 | StringLibrary = new StringLibrary(this); 40 | 41 | Globals = new LuaTable(); 42 | BaseLibrary.Setup(Globals); 43 | //StringLibrary.Setup(StringGlobals); 44 | } 45 | 46 | internal LuaTable GetTypeMetatable(object obj) 47 | { 48 | if (obj == null) 49 | return null; 50 | 51 | LuaTable table; 52 | if (Metatables.TryGetValue(obj.GetType(), out table)) 53 | return table; 54 | 55 | throw new ArgumentOutOfRangeException("obj", "Argument is of non-supported type"); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /IronLua/Runtime/DynamicCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.Linq.Expressions; 5 | using IronLua.Runtime.Binder; 6 | 7 | namespace IronLua.Runtime 8 | { 9 | // TODO: Make thread-safe 10 | class DynamicCache 11 | { 12 | readonly Context context; 13 | readonly Dictionary binaryOperationBinders; 14 | readonly Dictionary unaryOperationBinders; 15 | readonly Dictionary invokeMemberBinders; 16 | readonly Dictionary invokeBinders; 17 | readonly Dictionary convertBinders; 18 | readonly Dictionary setMemberBinders; 19 | readonly Dictionary getMemberBinders; 20 | LuaSetIndexBinder setIndexBinder; 21 | LuaGetIndexBinder getIndexBinder; 22 | 23 | Func getDynamicIndexCache; 24 | Func getDynamicNewIndexCache; 25 | Func getDynamicCallCache0; 26 | Func getDynamicCallCache1; 27 | Func getDynamicCallCache2; 28 | Func getDynamicCallCache3; 29 | 30 | public DynamicCache(Context context) 31 | { 32 | this.context = context; 33 | binaryOperationBinders = new Dictionary(); 34 | unaryOperationBinders = new Dictionary(); 35 | invokeMemberBinders = new Dictionary(); 36 | invokeBinders = new Dictionary(); 37 | convertBinders = new Dictionary(); 38 | setMemberBinders = new Dictionary(); 39 | getMemberBinders = new Dictionary(); 40 | } 41 | 42 | public BinaryOperationBinder GetBinaryOperationBinder(ExpressionType operation) 43 | { 44 | return GetCachedBinder(binaryOperationBinders, operation, k => new LuaBinaryOperationBinder(context, k)); 45 | } 46 | 47 | public UnaryOperationBinder GetUnaryOperationBinder(ExpressionType operation) 48 | { 49 | return GetCachedBinder(unaryOperationBinders, operation, k => new LuaUnaryOperationBinder(context, k)); 50 | } 51 | 52 | public InvokeMemberBinder GetInvokeMemberBinder(string name, CallInfo info) 53 | { 54 | return GetCachedBinder(invokeMemberBinders, new InvokeMemberBinderKey(name, info), 55 | k => new LuaInvokeMemberBinder(context, k.Name, k.Info)); 56 | } 57 | 58 | public InvokeBinder GetInvokeBinder(CallInfo callInfo) 59 | { 60 | return GetCachedBinder(invokeBinders, callInfo, k => new LuaInvokeBinder(context, k)); 61 | } 62 | 63 | public ConvertBinder GetConvertBinder(Type type) 64 | { 65 | return GetCachedBinder(convertBinders, type, k => new LuaConvertBinder(k)); 66 | } 67 | 68 | public SetMemberBinder GetSetMemberBinder(string name) 69 | { 70 | return GetCachedBinder(setMemberBinders, name, k => new LuaSetMemberBinder(k)); 71 | } 72 | 73 | public SetIndexBinder GetSetIndexBinder() 74 | { 75 | return setIndexBinder ?? (setIndexBinder = new LuaSetIndexBinder(context)); 76 | } 77 | 78 | public GetMemberBinder GetGetMemberBinder(string name) 79 | { 80 | return GetCachedBinder(getMemberBinders, name, k => new LuaGetMemberBinder(k)); 81 | } 82 | 83 | public GetIndexBinder GetGetIndexBinder() 84 | { 85 | return getIndexBinder ?? (getIndexBinder = new LuaGetIndexBinder(context)); 86 | } 87 | 88 | TValue GetCachedBinder(Dictionary cache, TKey key, Func newer) 89 | { 90 | TValue binder; 91 | if (cache.TryGetValue(key, out binder)) 92 | return binder; 93 | return cache[key] = newer(key); 94 | } 95 | 96 | // Stolen from DLR's reference implementation Sympl 97 | class InvokeMemberBinderKey 98 | { 99 | public string Name { get; private set; } 100 | public CallInfo Info { get; private set; } 101 | 102 | public InvokeMemberBinderKey(string name, CallInfo info) 103 | { 104 | Name = name; 105 | Info = info; 106 | } 107 | 108 | public override bool Equals(object obj) 109 | { 110 | var key = obj as InvokeMemberBinderKey; 111 | return key != null && Name == key.Name && Info.Equals(key.Info); 112 | } 113 | 114 | public override int GetHashCode() 115 | { 116 | return 0x28000000 ^ Name.GetHashCode() ^ Info.GetHashCode(); 117 | } 118 | } 119 | 120 | public Func GetDynamicIndex() 121 | { 122 | if (getDynamicIndexCache != null) 123 | return getDynamicIndexCache; 124 | 125 | var objVar = Expression.Parameter(typeof(object)); 126 | var keyVar = Expression.Parameter(typeof(object)); 127 | var expr = Expression.Lambda>( 128 | Expression.Dynamic(Context.DynamicCache.GetGetIndexBinder(), typeof(object), objVar, keyVar), 129 | objVar, keyVar); 130 | 131 | return getDynamicIndexCache = expr.Compile(); 132 | } 133 | 134 | public Func GetDynamicNewIndex() 135 | { 136 | if (getDynamicNewIndexCache != null) 137 | return getDynamicNewIndexCache; 138 | 139 | var objVar = Expression.Parameter(typeof(object)); 140 | var keyVar = Expression.Parameter(typeof(object)); 141 | var valueVar = Expression.Parameter(typeof(object)); 142 | var expr = Expression.Lambda>( 143 | Expression.Dynamic(Context.DynamicCache.GetSetIndexBinder(), typeof(object), objVar, keyVar, valueVar), 144 | objVar, keyVar, valueVar); 145 | 146 | return getDynamicNewIndexCache = expr.Compile(); 147 | } 148 | 149 | public Func GetDynamicCall0() 150 | { 151 | if (getDynamicCallCache0 != null) 152 | return getDynamicCallCache0; 153 | 154 | var funcVar = Expression.Parameter(typeof(object)); 155 | var expr = Expression.Lambda>( 156 | Expression.Dynamic(Context.DynamicCache.GetInvokeBinder(new CallInfo(0)), typeof(object), funcVar), funcVar); 157 | 158 | return getDynamicCallCache0 = expr.Compile(); 159 | } 160 | 161 | public Func GetDynamicCall1() 162 | { 163 | if (getDynamicCallCache1 != null) 164 | return getDynamicCallCache1; 165 | 166 | var funcVar = Expression.Parameter(typeof(object)); 167 | var argVar = Expression.Parameter(typeof(object)); 168 | var expr = Expression.Lambda>( 169 | Expression.Dynamic(Context.DynamicCache.GetInvokeBinder(new CallInfo(1)), typeof(object), funcVar, argVar), 170 | funcVar, argVar); 171 | 172 | return getDynamicCallCache1 = expr.Compile(); 173 | } 174 | 175 | public Func GetDynamicCall2() 176 | { 177 | if (getDynamicCallCache2 != null) 178 | return getDynamicCallCache2; 179 | 180 | var funcVar = Expression.Parameter(typeof(object)); 181 | var arg1Var = Expression.Parameter(typeof(object)); 182 | var arg2Var = Expression.Parameter(typeof(object)); 183 | 184 | var expr = Expression.Lambda>( 185 | Expression.Dynamic(Context.DynamicCache.GetInvokeBinder(new CallInfo(2)), typeof(object), funcVar, arg1Var, arg2Var), 186 | funcVar, arg1Var, arg2Var); 187 | 188 | return getDynamicCallCache2 = expr.Compile(); 189 | } 190 | 191 | public Func GetDynamicCall3() 192 | { 193 | if (getDynamicCallCache3 != null) 194 | return getDynamicCallCache3; 195 | 196 | var funcVar = Expression.Parameter(typeof(object)); 197 | var arg1Var = Expression.Parameter(typeof(object)); 198 | var arg2Var = Expression.Parameter(typeof(object)); 199 | var arg3Var = Expression.Parameter(typeof(object)); 200 | 201 | var expr = Expression.Lambda>( 202 | Expression.Dynamic(Context.DynamicCache.GetInvokeBinder(new CallInfo(3)), typeof(object), funcVar, arg1Var, arg2Var, arg3Var), 203 | funcVar, arg1Var, arg2Var, arg3Var); 204 | 205 | return getDynamicCallCache3 = expr.Compile(); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /IronLua/Runtime/LuaOps.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using IronLua.Library; 7 | using IronLua.Runtime.Binder; 8 | using Expr = System.Linq.Expressions.Expression; 9 | using ExprType = System.Linq.Expressions.ExpressionType; 10 | 11 | namespace IronLua.Runtime 12 | { 13 | static class LuaOps 14 | { 15 | public static bool Not(object value) 16 | { 17 | return value != null && (!(value is bool) || (bool)value); 18 | } 19 | 20 | public static object Length(Context context, object obj) 21 | { 22 | string str; 23 | LuaTable table; 24 | 25 | if ((str = obj as string) != null) 26 | return str.Length; 27 | if ((table = obj as LuaTable) != null) 28 | return table.Length(); 29 | 30 | return LengthMetamethod(context, obj); 31 | } 32 | 33 | public static object Concat(Context context, object left, object right) 34 | { 35 | if ((left is string || left is double) && (right is double || right is string)) 36 | return String.Concat(left, right); 37 | 38 | return ConcatMetamethod(context, left, right); 39 | } 40 | 41 | public static object LengthMetamethod(Context context, object obj) 42 | { 43 | var metamethod = GetMetamethod(context, obj, Constant.LENGTH_METAMETHOD); 44 | if (metamethod != null) 45 | return Context.DynamicCache.GetDynamicCall1()(metamethod, obj); 46 | 47 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "get length of", BaseLibrary.Type(obj)); 48 | } 49 | 50 | public static object UnaryMinusMetamethod(Context context, object obj) 51 | { 52 | var metamethod = GetMetamethod(context, obj, Constant.UNARYMINUS_METAMETHOD); 53 | if (metamethod != null) 54 | return Context.DynamicCache.GetDynamicCall1()(metamethod, obj); 55 | 56 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "perform arithmetic on", BaseLibrary.Type(obj)); 57 | } 58 | 59 | public static object IndexMetamethod(Context context, object obj, object key) 60 | { 61 | var metamethod = GetMetamethod(context, obj, Constant.INDEX_METAMETHOD); 62 | 63 | if (metamethod != null) 64 | { 65 | if (metamethod is Delegate) 66 | return Context.DynamicCache.GetDynamicCall2()(metamethod, obj, key); 67 | if (metamethod is LuaTable) 68 | return Context.DynamicCache.GetDynamicIndex()(obj, key); 69 | } 70 | 71 | if (obj is LuaTable) 72 | return null; 73 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "index", BaseLibrary.Type(obj)); 74 | } 75 | 76 | public static object NewIndexMetamethod(Context context, object obj, object key, object value) 77 | { 78 | var metamethod = GetMetamethod(context, obj, Constant.NEWINDEX_METAMETHOD); 79 | 80 | if (metamethod != null) 81 | { 82 | if (metamethod is Delegate) 83 | return Context.DynamicCache.GetDynamicCall3()(metamethod, obj, key, value); 84 | if (metamethod is LuaTable) 85 | return Context.DynamicCache.GetDynamicNewIndex()(obj, key, value); 86 | } 87 | 88 | if (obj is LuaTable) 89 | return null; 90 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "index", BaseLibrary.Type(obj)); 91 | } 92 | 93 | public static object CallMetamethod(Context context, object obj, object[] args) 94 | { 95 | var metamethod = GetMetamethod(context, obj, Constant.CALL_METAMETHOD); 96 | if (metamethod != null) 97 | { 98 | var array = new object[args.Length + 1]; 99 | array[0] = obj; 100 | Array.Copy(args, 0, array, 1, args.Length); 101 | return Context.DynamicCache.GetDynamicCall1()(metamethod, new Varargs(array)); 102 | } 103 | 104 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "call", BaseLibrary.Type(obj)); 105 | } 106 | 107 | public static object ConcatMetamethod(Context context, object left, object right) 108 | { 109 | var metamethod = GetMetamethod(context, left, Constant.CONCAT_METAMETHOD) ?? 110 | GetMetamethod(context, right, Constant.CONCAT_METAMETHOD); 111 | if (metamethod != null) 112 | return Context.DynamicCache.GetDynamicCall2()(metamethod, left, right); 113 | 114 | var typeName = left is string ? BaseLibrary.Type(left) : BaseLibrary.Type(right); 115 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "concatenate", typeName); 116 | } 117 | 118 | public static object BinaryOpMetamethod(Context context, ExprType op, object left, object right) 119 | { 120 | switch (op) 121 | { 122 | case ExprType.Add: 123 | case ExprType.Subtract: 124 | case ExprType.Multiply: 125 | case ExprType.Divide: 126 | case ExprType.Modulo: 127 | case ExprType.Power: 128 | return NumericMetamethod(context, op, left, right); 129 | 130 | case ExprType.GreaterThan: 131 | case ExprType.GreaterThanOrEqual: 132 | case ExprType.LessThan: 133 | case ExprType.LessThanOrEqual: 134 | return RelationalMetamethod(context, op, left, right); 135 | 136 | default: 137 | throw new ArgumentOutOfRangeException("op"); 138 | } 139 | } 140 | 141 | public static object NumericMetamethod(Context context, ExprType op, object left, object right) 142 | { 143 | var methodName = GetMethodName(op); 144 | 145 | var metamethod = GetMetamethod(context, left, methodName) ?? GetMetamethod(context, right, methodName); 146 | if (metamethod != null) 147 | return Context.DynamicCache.GetDynamicCall2()(metamethod, left, right); 148 | 149 | var typeName = BaseLibrary.Type(BaseLibrary.ToNumber(left) == null ? left : right); 150 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_ERROR, "perform arithmetic on", typeName); 151 | } 152 | 153 | public static object RelationalMetamethod(Context context, ExprType op, object left, object right) 154 | { 155 | if (left.GetType() != right.GetType()) 156 | return false; 157 | 158 | // There are no metamethods for 'a > b' and 'a >= b' so they are translated to 'b < a' and 'b <= a' respectively 159 | var invert = op == ExprType.GreaterThan || op == ExprType.GreaterThanOrEqual; 160 | 161 | var metamethod = GetRelationalMetamethod(context, op, left, right); 162 | 163 | if (metamethod != null) 164 | { 165 | if (invert) 166 | Context.DynamicCache.GetDynamicCall2()(metamethod, right, left); 167 | else 168 | Context.DynamicCache.GetDynamicCall2()(metamethod, left, right); 169 | } 170 | 171 | // In the absence of a '<=' metamethod, try '<', 'a <= b' is translated to 'not (b < a)' 172 | if (op != ExprType.LessThanOrEqual && op != ExprType.GreaterThanOrEqual) 173 | return false; 174 | 175 | metamethod = GetRelationalMetamethod(context, ExprType.LessThan, left, right); 176 | if (metamethod != null) 177 | { 178 | if (invert) 179 | Not(Context.DynamicCache.GetDynamicCall2()(metamethod, right, left)); 180 | else 181 | Not(Context.DynamicCache.GetDynamicCall2()(metamethod, left, right)); 182 | } 183 | 184 | var leftTypeName = BaseLibrary.Type(left); 185 | var rightTypeName = BaseLibrary.Type(right); 186 | 187 | if (leftTypeName == rightTypeName) 188 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_TWO_ERROR, "compare", leftTypeName); 189 | throw new LuaRuntimeException(ExceptionMessage.OP_TYPE_WITH_ERROR, "compare", leftTypeName, rightTypeName); 190 | } 191 | 192 | static object GetRelationalMetamethod(Context context, ExprType op, object left, object right) 193 | { 194 | var methodName = GetMethodName(op); 195 | var metamethodLeft = GetMetamethod(context, left, methodName); 196 | var metamethodRight = GetMetamethod(context, right, methodName); 197 | return metamethodLeft != metamethodRight ? null : metamethodLeft; 198 | } 199 | 200 | static string GetMethodName(ExprType op) 201 | { 202 | string methodName; 203 | return Constant.METAMETHODS.TryGetValue(op, out methodName) ? methodName : null; 204 | } 205 | 206 | public static object GetMetamethod(Context context, object obj, string methodName) 207 | { 208 | LuaTable table; 209 | 210 | if ((table = obj as LuaTable) != null) 211 | table = table.Metatable; 212 | else if (context != null) 213 | table = context.GetTypeMetatable(obj); 214 | 215 | return methodName == null || table == null ? null : table.GetValue(methodName); 216 | } 217 | 218 | public static void VarargsAssign(IRuntimeVariables variables, object[] values) 219 | { 220 | var variablesArray = VarargsAssign(variables.Count, values); 221 | for (var i = 0; i < variables.Count; i++) 222 | variables[i] = variablesArray[i]; 223 | } 224 | 225 | public static object[] VarargsAssign(int numVariables, object[] values) 226 | { 227 | var variables = new object[numVariables]; 228 | AssignValuesToVariables(variables, values, 0); 229 | return variables; 230 | } 231 | 232 | static void AssignValuesToVariables(object[] variables, IList values, int varCount) 233 | { 234 | Varargs varargs; 235 | 236 | for (var valueCount = 0; valueCount < values.Count && varCount < variables.Length; valueCount++, varCount++) 237 | { 238 | var value = values[valueCount]; 239 | if ((varargs = value as Varargs) != null) 240 | { 241 | // Expand varargs if it's the last value otherwise just take the first value in varargs 242 | if (valueCount + 1 == values.Count) 243 | AssignValuesToVariables(variables, varargs, varCount); 244 | else 245 | variables[varCount] = varargs.First(); 246 | } 247 | else 248 | { 249 | variables[varCount] = value; 250 | } 251 | } 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /IronLua/Runtime/LuaTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Dynamic; 5 | using System.Linq; 6 | using IronLua.Runtime.Binder; 7 | using IronLua.Util; 8 | using Expr = System.Linq.Expressions.Expression; 9 | using ExprType = System.Linq.Expressions.ExpressionType; 10 | 11 | namespace IronLua.Runtime 12 | { 13 | #if DEBUG 14 | [DebuggerTypeProxy(typeof(LuaTableDebugView))] 15 | #endif 16 | class LuaTable : IDynamicMetaObjectProvider 17 | { 18 | int[] buckets; 19 | Entry[] entries; 20 | int freeList; 21 | int freeCount; 22 | int count; 23 | 24 | public LuaTable() 25 | { 26 | const int prime = 3; 27 | 28 | buckets = new int[prime]; 29 | for (var i = 0; i < buckets.Length; i++) 30 | buckets[i] = -1; 31 | 32 | entries = new Entry[prime]; 33 | freeList = -1; 34 | } 35 | 36 | public LuaTable Metatable { get; set; } 37 | 38 | public DynamicMetaObject GetMetaObject(Expr parameter) 39 | { 40 | return new MetaTable(parameter, BindingRestrictions.Empty, this); 41 | } 42 | 43 | internal Varargs Next(object index = null) 44 | { 45 | if (index == null) 46 | { 47 | for (var i = 0; i < entries.Length; i++) 48 | { 49 | if (entries[i].Key != null) 50 | return new Varargs(entries[i].Key, entries[i].Value); 51 | } 52 | return null; 53 | } 54 | 55 | for (var i = FindEntry(index) + 1; i < entries.Length; i++) 56 | { 57 | if (entries[i].Key != null) 58 | return new Varargs(entries[i].Key, entries[i].Value); 59 | } 60 | return null; 61 | } 62 | 63 | internal object SetValue(object key, object value) 64 | { 65 | if (value == null) 66 | { 67 | Remove(key); 68 | return null; 69 | } 70 | 71 | var hashCode = key.GetHashCode() & Int32.MaxValue; 72 | var modHashCode = hashCode % buckets.Length; 73 | 74 | for (var i = buckets[modHashCode]; i >= 0; i = entries[i].Next) 75 | { 76 | if (entries[i].HashCode == hashCode && entries[i].Key.Equals(key)) 77 | { 78 | entries[i].Value = value; 79 | return value; 80 | } 81 | } 82 | 83 | int free; 84 | if (freeCount > 0) 85 | { 86 | free = freeList; 87 | freeList = entries[free].Next; 88 | freeCount--; 89 | } 90 | else 91 | { 92 | if (count == entries.Length) 93 | { 94 | Resize(); 95 | modHashCode = hashCode % buckets.Length; 96 | } 97 | free = count; 98 | count++; 99 | } 100 | 101 | entries[free].HashCode = hashCode; 102 | entries[free].Next = buckets[modHashCode]; 103 | entries[free].Key = key; 104 | entries[free].Value = value; 105 | buckets[modHashCode] = free; 106 | return value; 107 | } 108 | 109 | internal object GetValue(object key) 110 | { 111 | var pos = FindEntry(key); 112 | return pos < 0 ? null : entries[pos].Value; 113 | } 114 | 115 | void Remove(object key) 116 | { 117 | var hashCode = key.GetHashCode() & Int32.MaxValue; 118 | var modHashCode = hashCode % buckets.Length; 119 | var last = -1; 120 | 121 | for (var i = buckets[modHashCode]; i >= 0; i = entries[i].Next) 122 | { 123 | if (entries[i].HashCode == hashCode && entries[i].Key.Equals(key)) 124 | { 125 | if (last < 0) 126 | buckets[modHashCode] = entries[i].Next; 127 | else 128 | entries[last].Next = entries[i].Next; 129 | 130 | entries[i].HashCode = -1; 131 | entries[i].Next = freeList; 132 | entries[i].Key = null; 133 | entries[i].Value = null; 134 | freeList = i; 135 | freeCount++; 136 | return; 137 | } 138 | last = i; 139 | } 140 | } 141 | 142 | int FindEntry(object key) 143 | { 144 | var hashCode = key.GetHashCode() & Int32.MaxValue; 145 | var modHashCode = hashCode % buckets.Length; 146 | 147 | for (var i = buckets[modHashCode]; i >= 0; i = entries[i].Next) 148 | { 149 | if (entries[i].HashCode == hashCode && entries[i].Key.Equals(key)) 150 | return i; 151 | } 152 | 153 | return -1; 154 | } 155 | 156 | void Resize() 157 | { 158 | var prime = HashHelpers.GetPrime(count * 2); 159 | 160 | var newBuckets = new int[prime]; 161 | for (var i = 0; i < newBuckets.Length; i++) 162 | newBuckets[i] = -1; 163 | 164 | var newEntries = new Entry[prime]; 165 | Array.Copy(entries, 0, newEntries, 0, count); 166 | for (var i = 0; i < count; i++) 167 | { 168 | var modHashCode = newEntries[i].HashCode % prime; 169 | newEntries[i].Next = newBuckets[modHashCode]; 170 | newBuckets[modHashCode] = i; 171 | } 172 | 173 | buckets = newBuckets; 174 | entries = newEntries; 175 | } 176 | 177 | internal int Length() 178 | { 179 | var lastNum = 0; 180 | foreach (var key in entries.Select(e => e.Key).OfType().OrderBy(key => key)) 181 | { 182 | var intKey = (int)key; 183 | 184 | if (intKey > lastNum + 1) 185 | return lastNum; 186 | if (intKey != key) 187 | continue; 188 | 189 | lastNum = intKey; 190 | } 191 | return lastNum; 192 | } 193 | 194 | struct Entry 195 | { 196 | public int HashCode; 197 | public object Key; 198 | public object Value; 199 | public int Next; 200 | } 201 | 202 | class MetaTable : DynamicMetaObject 203 | { 204 | public MetaTable(Expr expression, BindingRestrictions restrictions, LuaTable value) 205 | : base(expression, restrictions, value) 206 | { 207 | } 208 | 209 | public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) 210 | { 211 | if (!LuaBinaryOperationBinder.BinaryExprTypes.ContainsKey(binder.Operation)) 212 | throw new Exception(); // TODO 213 | 214 | var expression = MetamethodFallbacks.BinaryOp(null, binder.Operation, this, arg); 215 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 216 | } 217 | 218 | public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) 219 | { 220 | if (binder.Operation != ExprType.Negate) 221 | throw new Exception(); // TODO 222 | 223 | var expression = MetamethodFallbacks.UnaryMinus(null, this); 224 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 225 | } 226 | 227 | public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) 228 | { 229 | var expression = MetamethodFallbacks.Call(null, this, args); 230 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 231 | } 232 | 233 | public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) 234 | { 235 | var expression = Expr.Dynamic(new LuaGetMemberBinder(binder.Name), typeof(object), Expression); 236 | return binder.FallbackInvoke(new DynamicMetaObject(expression, Restrictions), args, null); 237 | } 238 | 239 | public override DynamicMetaObject BindGetMember(GetMemberBinder binder) 240 | { 241 | var expression = Expr.Call( 242 | Expr.Convert(Expression, typeof(LuaTable)), 243 | MemberInfos.LuaTableGetValue, 244 | Expr.Constant(binder.Name)); 245 | 246 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 247 | } 248 | 249 | public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) 250 | { 251 | var expression = Expr.Call( 252 | Expr.Convert(Expression, typeof(LuaTable)), 253 | MemberInfos.LuaTableSetValue, 254 | Expr.Constant(binder.Name), 255 | Expr.Convert(value.Expression, typeof(object))); 256 | 257 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 258 | } 259 | 260 | public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) 261 | { 262 | var valueVar = Expr.Variable(typeof(object)); 263 | 264 | var getValue = Expr.Call( 265 | Expr.Convert(Expression, typeof(LuaTable)), 266 | MemberInfos.LuaTableGetValue, 267 | Expr.Convert(indexes[0].Expression, typeof(object))); 268 | var valueAssign = Expr.Assign(valueVar, getValue); 269 | 270 | var expression = Expr.Block( 271 | valueVar, 272 | Expr.Condition( 273 | Expr.Equal(valueVar, Expr.Constant(null)), 274 | MetamethodFallbacks.Index(null, this, indexes), 275 | valueVar)); 276 | 277 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 278 | } 279 | 280 | public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) 281 | { 282 | var getValue = Expr.Call( 283 | Expr.Convert(Expression, typeof(LuaTable)), 284 | MemberInfos.LuaTableGetValue, 285 | Expr.Convert(indexes[0].Expression, typeof(object))); 286 | 287 | var setValue = Expr.Call( 288 | Expr.Convert(Expression, typeof(LuaTable)), 289 | MemberInfos.LuaTableSetValue, 290 | Expr.Convert(indexes[0].Expression, typeof(object)), 291 | Expr.Convert(value.Expression, typeof(object))); 292 | 293 | var expression = Expr.Condition( 294 | Expr.Equal(getValue, Expr.Constant(null)), 295 | MetamethodFallbacks.NewIndex(null, this, indexes, value), 296 | setValue); 297 | 298 | return new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this)); 299 | } 300 | } 301 | 302 | #if DEBUG 303 | class LuaTableDebugView 304 | { 305 | LuaTable table; 306 | 307 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 308 | public KeyValuePair[] Items 309 | { 310 | get 311 | { 312 | var index = 0; 313 | var pairs = new KeyValuePair[table.count]; 314 | 315 | for (var i = 0; i < table.count; i++) 316 | { 317 | if (table.entries[i].HashCode >= 0) 318 | pairs[index++] = new KeyValuePair(table.entries[i].Key, 319 | table.entries[i].Value); 320 | } 321 | 322 | return pairs; 323 | } 324 | } 325 | 326 | public LuaTableDebugView(LuaTable table) 327 | { 328 | this.table = table; 329 | } 330 | } 331 | #endif 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /IronLua/Runtime/MetamethodFallbacks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using System.Linq; 4 | using Expr = System.Linq.Expressions.Expression; 5 | using ExprType = System.Linq.Expressions.ExpressionType; 6 | 7 | namespace IronLua.Runtime 8 | { 9 | static class MetamethodFallbacks 10 | { 11 | public static Expr BinaryOp(Context context, ExprType operation, DynamicMetaObject left, DynamicMetaObject right) 12 | { 13 | return Expr.Invoke( 14 | Expr.Constant((Func)LuaOps.BinaryOpMetamethod), 15 | Expr.Constant(context, typeof(Context)), 16 | Expr.Constant(operation), 17 | Expr.Convert(left.Expression, typeof(object)), 18 | Expr.Convert(right.Expression, typeof(object))); 19 | } 20 | 21 | public static Expr Index(Context context, DynamicMetaObject target, DynamicMetaObject[] indexes) 22 | { 23 | return Expr.Invoke( 24 | Expr.Constant((Func)LuaOps.IndexMetamethod), 25 | Expr.Constant(context, typeof(Context)), 26 | Expr.Convert(target.Expression, typeof(object)), 27 | Expr.Convert(indexes[0].Expression, typeof(object))); 28 | } 29 | 30 | public static Expr Call(Context context, DynamicMetaObject target, DynamicMetaObject[] args) 31 | { 32 | var expression = Expr.Invoke( 33 | Expr.Constant((Func)LuaOps.CallMetamethod), 34 | Expr.Constant(context, typeof(Context)), 35 | Expr.Convert(target.Expression, typeof(object)), 36 | Expr.NewArrayInit( 37 | typeof(object), 38 | args.Select(arg => Expr.Convert(arg.Expression, typeof(object))))); 39 | 40 | return expression; 41 | } 42 | 43 | public static Expr NewIndex(Context context, DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value) 44 | { 45 | return Expr.Invoke( 46 | Expr.Constant((Func)LuaOps.NewIndexMetamethod), 47 | Expr.Constant(context, typeof(Context)), 48 | Expr.Convert(target.Expression, typeof(object)), 49 | Expr.Convert(indexes[0].Expression, typeof(object)), 50 | Expr.Convert(value.Expression, typeof(object))); 51 | } 52 | 53 | public static Expr UnaryMinus(Context context, DynamicMetaObject target) 54 | { 55 | return Expr.Invoke( 56 | Expr.Constant((Func)LuaOps.UnaryMinusMetamethod), 57 | Expr.Constant(context, typeof(Context)), 58 | Expr.Convert(target.Expression, typeof(object))); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /IronLua/Runtime/RuntimeHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Dynamic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | 6 | namespace IronLua.Runtime 7 | { 8 | static class RuntimeHelpers 9 | { 10 | public static BindingRestrictions MergeTypeRestrictions(DynamicMetaObject dmo1, DynamicMetaObject[] dmos) 11 | { 12 | var newDmos = new DynamicMetaObject[dmos.Length + 1]; 13 | newDmos[0] = dmo1; 14 | Array.Copy(dmos, 0, newDmos, 1, dmos.Length); 15 | return MergeTypeRestrictions(newDmos); 16 | } 17 | 18 | public static BindingRestrictions MergeTypeRestrictions(params DynamicMetaObject[] dmos) 19 | { 20 | var restrictions = BindingRestrictions.Combine(dmos); 21 | 22 | foreach (var dmo in dmos) 23 | { 24 | if (dmo.HasValue && dmo.Value == null) 25 | restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(dmo.Expression, dmo.Value)); 26 | else 27 | restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(dmo.Expression, dmo.LimitType)); 28 | } 29 | 30 | return restrictions; 31 | } 32 | 33 | public static BindingRestrictions MergeInstanceRestrictions(params DynamicMetaObject[] dmos) 34 | { 35 | var restrictions = BindingRestrictions.Combine(dmos); 36 | return dmos.Aggregate( 37 | restrictions, 38 | (current, dmo) => current.Merge(BindingRestrictions.GetInstanceRestriction(dmo.Expression, dmo.Value))); 39 | } 40 | 41 | public static bool TryGetFirstVarargs(DynamicMetaObject target, out DynamicMetaObject first) 42 | { 43 | if (target.LimitType != typeof(Varargs)) 44 | { 45 | first = target; 46 | return false; 47 | } 48 | 49 | Expression expr = Expression.Call(Expression.Convert(target.Expression, typeof(Varargs)), 50 | typeof(Varargs).GetMethod("First")); 51 | first = new DynamicMetaObject(expr, MergeTypeRestrictions(target)); 52 | return true; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /IronLua/Runtime/Varargs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace IronLua.Runtime 7 | { 8 | class Varargs : IList, IList 9 | { 10 | static readonly Varargs empty = new Varargs(); 11 | readonly object[] data; 12 | 13 | public Varargs(params object[] data) 14 | { 15 | this.data = data; 16 | } 17 | 18 | public Varargs(IEnumerable data) 19 | { 20 | this.data = data.ToArray(); 21 | } 22 | 23 | public int Count { get { return data.Length; } } 24 | 25 | public static Varargs Empty { get { return empty; } } 26 | 27 | public object First() 28 | { 29 | return data.Length > 0 ? data[0] : null; 30 | } 31 | 32 | public IEnumerator GetEnumerator() 33 | { 34 | return ((IEnumerable)data).GetEnumerator(); 35 | } 36 | 37 | IEnumerator IEnumerable.GetEnumerator() 38 | { 39 | return data.GetEnumerator(); 40 | } 41 | 42 | public void CopyTo(Array array, int index) 43 | { 44 | data.CopyTo(array, index); 45 | } 46 | 47 | bool ICollection.Remove(object item) 48 | { 49 | throw new InvalidOperationException("Varargs is readonly"); 50 | } 51 | 52 | int ICollection.Count 53 | { 54 | get { return data.Length; } 55 | } 56 | 57 | bool ICollection.IsReadOnly 58 | { 59 | get { return true; } 60 | } 61 | 62 | int ICollection.Count 63 | { 64 | get { return data.Length; } 65 | } 66 | 67 | public object SyncRoot 68 | { 69 | get { return this; } 70 | } 71 | 72 | public bool IsSynchronized 73 | { 74 | get { return false; } 75 | } 76 | 77 | public int Add(object value) 78 | { 79 | throw new InvalidOperationException("Varargs is readonly"); 80 | } 81 | 82 | void ICollection.Clear() 83 | { 84 | throw new InvalidOperationException("Varargs is readonly"); 85 | } 86 | 87 | bool ICollection.Contains(object item) 88 | { 89 | return data.Contains(item); 90 | } 91 | 92 | public void CopyTo(object[] array, int arrayIndex) 93 | { 94 | data.CopyTo(array, arrayIndex); 95 | } 96 | 97 | public bool Contains(object value) 98 | { 99 | return data.Contains(value); 100 | } 101 | 102 | void ICollection.Add(object item) 103 | { 104 | throw new InvalidOperationException("Varargs is readonly"); 105 | } 106 | 107 | void IList.Clear() 108 | { 109 | throw new InvalidOperationException("Varargs is readonly"); 110 | } 111 | 112 | public int IndexOf(object value) 113 | { 114 | for (int i=0; i.Insert(int index, object item) 123 | { 124 | throw new InvalidOperationException("Varargs is readonly"); 125 | } 126 | 127 | void IList.RemoveAt(int index) 128 | { 129 | throw new InvalidOperationException("Varargs is readonly"); 130 | } 131 | 132 | public object this[int index] 133 | { 134 | get { return data[index]; } 135 | set { throw new InvalidOperationException("Varargs is readonly"); } 136 | } 137 | 138 | int IList.IndexOf(object item) 139 | { 140 | return IndexOf(item); 141 | } 142 | 143 | public void Insert(int index, object value) 144 | { 145 | throw new InvalidOperationException("Varargs is readonly"); 146 | } 147 | 148 | public void Remove(object value) 149 | { 150 | throw new InvalidOperationException("Varargs is readonly"); 151 | } 152 | 153 | void IList.RemoveAt(int index) 154 | { 155 | throw new InvalidOperationException("Varargs is readonly"); 156 | } 157 | 158 | object IList.this[int index] 159 | { 160 | get { return data[index]; } 161 | set { throw new InvalidOperationException("Varargs is readonly"); } 162 | } 163 | 164 | bool IList.IsReadOnly 165 | { 166 | get { return true; } 167 | } 168 | 169 | public bool IsFixedSize 170 | { 171 | get { return true; } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /IronLua/Util/CharExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace IronLua.Util 2 | { 3 | static class CharExtensions 4 | { 5 | public static bool IsDecimal(this char c) 6 | { 7 | return c >= '0' && c <= '9'; 8 | } 9 | 10 | public static bool IsHex(this char c) 11 | { 12 | return 13 | (c >= '0' && c <= '9') || 14 | (c >= 'a' && c <= 'f') || 15 | (c >= 'A' && c <= 'F'); 16 | } 17 | 18 | public static bool IsPunctuation(this char c) 19 | { 20 | switch (c) 21 | { 22 | case '+': 23 | case '-': 24 | case '*': 25 | case '/': 26 | case '%': 27 | case '^': 28 | case '#': 29 | case '~': 30 | case '<': 31 | case '>': 32 | case '=': 33 | case '(': 34 | case ')': 35 | case '{': 36 | case '}': 37 | case '[': 38 | case ']': 39 | case ';': 40 | case ':': 41 | case ',': 42 | case '.': 43 | return true; 44 | default: 45 | return false; 46 | } 47 | } 48 | 49 | public static bool IsIdentifierStart(this char c) 50 | { 51 | return 52 | (c >= 'a' && c <= 'z') || 53 | (c >= 'A' && c <= 'Z') || 54 | (c == '_'); 55 | } 56 | 57 | public static bool IsIdentifier(this char c) 58 | { 59 | return 60 | (c >= 'a' && c <= 'z') || 61 | (c >= 'A' && c <= 'Z') || 62 | (c >= '0' && c <= '9') || 63 | (c == '_'); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /IronLua/Util/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace IronLua.Util 5 | { 6 | static class EnumerableExtensions 7 | { 8 | public static IEnumerable Add(this IEnumerable collection, T item) 9 | { 10 | foreach (var element in collection) 11 | yield return element; 12 | yield return item; 13 | } 14 | 15 | public static IEnumerable Resize(this IEnumerable collection, int size, T item) 16 | { 17 | var i = 0; 18 | foreach (var element in collection) 19 | { 20 | if (i++ >= size) 21 | yield break; 22 | yield return element; 23 | } 24 | 25 | for (; i < size; i++) 26 | yield return item; 27 | } 28 | 29 | public static IEnumerable Resize(this IEnumerable collection, int size, Func initalizer) 30 | { 31 | var i = 0; 32 | foreach (var element in collection) 33 | { 34 | if (i++ >= size) 35 | yield break; 36 | yield return element; 37 | } 38 | 39 | for (; i < size; i++) 40 | yield return initalizer(); 41 | } 42 | 43 | public static IEnumerable Resize(this IEnumerable collection, int size, Func initalizer) 44 | { 45 | var i = 0; 46 | foreach (var element in collection) 47 | { 48 | if (i++ >= size) 49 | yield break; 50 | yield return element; 51 | } 52 | 53 | for (; i < size; i++) 54 | yield return initalizer(i); 55 | } 56 | 57 | public static IEnumerable Resize(this IEnumerable collection, int size, IEnumerable padder) 58 | { 59 | var i = 0; 60 | foreach (var element in collection) 61 | { 62 | if (i++ >= size) 63 | yield break; 64 | yield return element; 65 | } 66 | 67 | foreach (var element in padder) 68 | { 69 | yield return element; 70 | i++; 71 | } 72 | 73 | if (i != size) 74 | throw new ArgumentException(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /IronLua/Util/HashHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace IronLua.Util 7 | { 8 | static class HashHelpers 9 | { 10 | public static int GetPrime(int min) 11 | { 12 | for (var i=0; i= min) 16 | return min; 17 | } 18 | 19 | for (var i=min | 1; i < Int32.MaxValue; i+=2) 20 | { 21 | if (IsPrime(i)) 22 | return i; 23 | } 24 | 25 | return min; 26 | } 27 | 28 | public static bool IsPrime(int candidate) 29 | { 30 | if ((candidate & 1) == 0) 31 | return candidate == 2; 32 | 33 | var num = (int)Math.Sqrt(candidate); 34 | for (var i = 3; i <= num; i += 2) 35 | { 36 | if (candidate%1 == 0) 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | static readonly int[] primes = 44 | new int[] 45 | { 46 | 3, 47 | 7, 48 | 11, 49 | 17, 50 | 23, 51 | 29, 52 | 37, 53 | 47, 54 | 59, 55 | 71, 56 | 89, 57 | 107, 58 | 131, 59 | 163, 60 | 197, 61 | 239, 62 | 293, 63 | 353, 64 | 431, 65 | 521, 66 | 631, 67 | 761, 68 | 919, 69 | 1103, 70 | 1327, 71 | 1597, 72 | 1931, 73 | 2333, 74 | 2801, 75 | 3371, 76 | 4049, 77 | 4861, 78 | 5839, 79 | 7013, 80 | 8419, 81 | 10103, 82 | 12143, 83 | 14591, 84 | 17519, 85 | 21023, 86 | 25229, 87 | 30293, 88 | 36353, 89 | 43627, 90 | 52361, 91 | 62851, 92 | 75431, 93 | 90523, 94 | 108631, 95 | 130363, 96 | 156437, 97 | 187751, 98 | 225307, 99 | 270371, 100 | 324449, 101 | 389357, 102 | 467237, 103 | 560689, 104 | 672827, 105 | 807403, 106 | 968897, 107 | 1162687, 108 | 1395263, 109 | 1674319, 110 | 2009191, 111 | 2411033, 112 | 2893249, 113 | 3471899, 114 | 4166287, 115 | 4999559, 116 | 5999471, 117 | 7199369 118 | }; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /IronLua/Util/ParameterInfoExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace IronLua.Util 5 | { 6 | static class ParameterInfoExtensions 7 | { 8 | public static bool IsParams(this ParameterInfo parameter) 9 | { 10 | return Attribute.IsDefined(parameter, typeof(ParamArrayAttribute)); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IronLua/Util/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IronLua.Util 4 | { 5 | static class TypeExtensions 6 | { 7 | public static object GetDefaultValue(this Type type) 8 | { 9 | return type.IsValueType ? Activator.CreateInstance(type) : null; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IronLua 2 | 3 | IronLua is intended to be a full implementation of Lua targeting .NET. Allowing easy embedding into applications and friction-less integration with .NET are key goals. 4 | 5 | It's built with C# on top of the Dynamic Language Runtime. 6 | 7 | Licensing has not been decided upon yet but it will be some form of [permissive free software license](http://en.wikipedia.org/wiki/Permissive_free_software_licence) for easy contribution and usage without any fuss. 8 | 9 | ## A work in progress 10 | 11 | *This is very much a work in progress project and isn't near a usable state yet.* 12 | 13 | * 2011-06-30
14 | Started work on lexer. 15 | 16 | * 2011-07-05
17 | Lexer has all major functionallity and can lex entire Lua. Still some bugs that will be fixed while working on parser.
18 | Started work on parser. 19 | 20 | * 2011-07-17
21 | Can parse entire Lua. Probably have lots of minor bugs that will be fixed when I pull in the test suites.
22 | Have begun reading up on DLR. Will probably take some time reading documentation of the DLR before I start working on the runtime and translation of the AST to DLR expressions. 23 | 24 | * 2011-08-09
25 | I have decided to rewrite the project in C#. It should be pretty straightforward to port. 26 | 27 | * 2011-08-15
28 | Rewrite to C# is done. The rewrite was done for several reasons. The binary size is 4 times smaller, probably because of F#'s discriminated unions and closure's generated code among other things. Additionally tooling is alot better for C# and it is easier to reason about code performance because the IL generated is more easily mapped to C#. 29 | 30 | * 2011-09-14
31 | IronLua can now generate expression trees for its entire AST. Currently working on function invokation, specifically mapping arguments to parameters. It's a quite a complex process involving type coercion and casting, expanding varargs, using parameter and type default values if not enough parameters and wrapping overflowing arguments into "params" and Varargs parameters.
32 | After that I will start working on all the TODO comments and get proper exception and error code everywhere. Then it's time to implement the entire Lua standard library, some parts will probably be left unimplemented like parts of the debug package and coroutines might not be implemented for the 0.1.0 release. Finally I will create the test harness and hopefully find some useable test code I can bring in. And that's pretty much it for the 0.1.0 release. Full .NET integration and proper error messages/stack traces is slated for 0.2.0 and possibly 0.3.0. -------------------------------------------------------------------------------- /Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Sample 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Sample")] 9 | [assembly: AssemblyDescription("Sample application for IronLua")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Sample")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b3b9952b-8a38-40c8-a762-5e9524b00a8f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Sample/Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {FDD11759-02FA-44BF-84C6-2F5B2AA5B6BC} 9 | Exe 10 | Properties 11 | Sample 12 | Sample 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | true 38 | bin\x86\Debug\ 39 | DEBUG;TRACE 40 | full 41 | x86 42 | bin\Debug\Sample.exe.CodeAnalysisLog.xml 43 | true 44 | GlobalSuppressions.cs 45 | prompt 46 | MinimumRecommendedRules.ruleset 47 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 48 | true 49 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 50 | true 51 | false 52 | 53 | 54 | bin\x86\Release\ 55 | TRACE 56 | true 57 | pdbonly 58 | x86 59 | bin\Release\Sample.exe.CodeAnalysisLog.xml 60 | true 61 | GlobalSuppressions.cs 62 | prompt 63 | MinimumRecommendedRules.ruleset 64 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 65 | true 66 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 67 | true 68 | 69 | 70 | 71 | ..\packages\Mono.Linq.Expressions.1.1.0.0\lib\Mono.Linq.Expressions.dll 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | {F166178F-729B-4DB5-8D7C-13C269FB5039} 88 | IronLua 89 | 90 | 91 | 92 | 93 | 94 | 95 | 102 | -------------------------------------------------------------------------------- /Sample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Mono.Linq.Expressions.1.1.0.0/Mono.Linq.Expressions.1.1.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericmj/IronLua/e8e511f53243b87dcd44f473ab64472315666e9b/packages/Mono.Linq.Expressions.1.1.0.0/Mono.Linq.Expressions.1.1.0.0.nupkg -------------------------------------------------------------------------------- /packages/Mono.Linq.Expressions.1.1.0.0/lib/Mono.Linq.Expressions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericmj/IronLua/e8e511f53243b87dcd44f473ab64472315666e9b/packages/Mono.Linq.Expressions.1.1.0.0/lib/Mono.Linq.Expressions.dll -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------