diff --git a/src/MoonSharp.Interpreter/Tree/Expression_.cs b/src/MoonSharp.Interpreter/Tree/Expression_.cs index d0235bbb..f33d26ca 100644 --- a/src/MoonSharp.Interpreter/Tree/Expression_.cs +++ b/src/MoonSharp.Interpreter/Tree/Expression_.cs @@ -1,6 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Tree.Expressions; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution.VM; namespace MoonSharp.Interpreter.Tree { @@ -17,6 +20,18 @@ public virtual string GetFriendlyDebugName() public abstract DynValue Eval(ScriptExecutionContext context); + public abstract bool EvalLiteral(out DynValue dv); + + public void CompilePossibleLiteral(ByteCode bc) + { + if (EvalLiteral(out var dv)) + { + if(dv == null) throw new NullReferenceException("Invalid literal: null"); + bc.Emit_Literal(dv); + } + else Compile(bc); + } + public virtual SymbolRef FindDynamic(ScriptExecutionContext context) { return null; diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/AdjustmentExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/AdjustmentExpression.cs index 26489201..821cd214 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/AdjustmentExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/AdjustmentExpression.cs @@ -1,4 +1,5 @@ -using MoonSharp.Interpreter.Execution; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions @@ -23,5 +24,15 @@ public override DynValue Eval(ScriptExecutionContext context) { return expression.Eval(context).ToScalar(); } + + public override bool EvalLiteral(out DynValue dv) + { + if (expression.EvalLiteral(out dv)) + { + dv = dv.ToScalar(); + return true; + } + return false; + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs index 255039f5..3c80b19e 100755 --- a/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs @@ -1,4 +1,5 @@ using System; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Execution.VM; @@ -299,12 +300,12 @@ private static OpCode OperatorToOpCode(Operator op) public override void Compile(Execution.VM.ByteCode bc) { - m_Exp1.Compile(bc); + m_Exp1.CompilePossibleLiteral(bc); if (m_Operator == Operator.Or) { Instruction i = bc.Emit_Jump(OpCode.JtOrPop, -1); - m_Exp2.Compile(bc); + m_Exp2.CompilePossibleLiteral(bc); i.NumVal = bc.GetJumpPointForNextInstruction(); return; } @@ -312,7 +313,7 @@ public override void Compile(Execution.VM.ByteCode bc) if (m_Operator == Operator.And) { Instruction i = bc.Emit_Jump(OpCode.JfOrPop, -1); - m_Exp2.Compile(bc); + m_Exp2.CompilePossibleLiteral(bc); i.NumVal = bc.GetJumpPointForNextInstruction(); return; } @@ -320,7 +321,7 @@ public override void Compile(Execution.VM.ByteCode bc) if (m_Exp2 != null) { - m_Exp2.Compile(bc); + m_Exp2.CompilePossibleLiteral(bc); } bc.Emit_Operator(OperatorToOpCode(m_Operator)); @@ -329,6 +330,50 @@ public override void Compile(Execution.VM.ByteCode bc) bc.Emit_Operator(OpCode.Not); } + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + if (!m_Exp1.EvalLiteral(out var v1)) + return false; + v1 = v1.ToScalar(); + if (!m_Exp2.EvalLiteral(out var v2)) + return false; + v2 = v2.ToScalar(); + if (m_Operator == Operator.Or) + { + if (v1.CastToBool()) + dv = v1; + else + dv = v2; + } + else if (m_Operator == Operator.And) + { + if (!v1.CastToBool()) + dv = v1; + else + dv = v2; + } + else if ((m_Operator & COMPARES) != 0) + { + dv = DynValue.NewBoolean(EvalComparison(v1, v2, m_Operator)); + } + else if (m_Operator == Operator.StrConcat) + { + string s1 = v1.CastToString(); + string s2 = v2.CastToString(); + + if (s1 == null || s2 == null) + throw new DynamicExpressionException("Attempt to perform concatenation on non-strings."); + + dv = DynValue.NewString(s1 + s2); + } + else + { + dv = DynValue.NewNumber(EvalArithmetic(v1, v2)); + } + return true; + } + public override DynValue Eval(ScriptExecutionContext context) { DynValue v1 = m_Exp1.Eval(context).ToScalar(); @@ -398,6 +443,8 @@ private double EvalArithmetic(DynValue v1, DynValue v2) if (mod < 0) mod += d2; return mod; } + case Operator.Power: + return Math.Pow(d1, d2); default: throw new DynamicExpressionException("Unsupported operator {0}", m_Operator); } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/DynamicExprExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/DynamicExprExpression.cs index 80a5491a..46f6359e 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/DynamicExprExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/DynamicExprExpression.cs @@ -1,4 +1,5 @@ using System; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions @@ -20,6 +21,11 @@ public override DynValue Eval(ScriptExecutionContext context) return m_Exp.Eval(context); } + public override bool EvalLiteral(out DynValue dv) + { + throw new InvalidOperationException(); + } + public override void Compile(Execution.VM.ByteCode bc) { throw new InvalidOperationException(); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/ExprListExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/ExprListExpression.cs index c300a618..6e8e8110 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/ExprListExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/ExprListExpression.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions @@ -22,7 +23,7 @@ public Expression[] GetExpressions() public override void Compile(Execution.VM.ByteCode bc) { foreach (var exp in expressions) - exp.Compile(bc); + exp.CompilePossibleLiteral(bc); if (expressions.Count > 1) bc.Emit_MkTuple(expressions.Count); @@ -35,5 +36,11 @@ public override DynValue Eval(ScriptExecutionContext context) return DynValue.Void; } + + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs index e0e8018f..67d94fe5 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionCallExpression.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Debugging; using MoonSharp.Interpreter.Execution; @@ -80,8 +81,9 @@ public override void Compile(Execution.VM.ByteCode bc) ++argslen; } + for (int i = 0; i < m_Arguments.Count; i++) - m_Arguments[i].Compile(bc); + m_Arguments[i].CompilePossibleLiteral(bc); if (!string.IsNullOrEmpty(m_Name)) { @@ -93,6 +95,12 @@ public override void Compile(Execution.VM.ByteCode bc) } } + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } + public override DynValue Eval(ScriptExecutionContext context) { throw new DynamicExpressionException("Dynamic Expressions cannot call functions."); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs index 3146cedb..8f450b51 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/FunctionDefinitionExpression.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Debugging; using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Execution.VM; @@ -250,6 +251,12 @@ public int Compile(ByteCode bc, Func afterDecl, string friendlyName) return CompileBody(bc, friendlyName); } + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } + public override void Compile(ByteCode bc) { diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs index 1e81aeaf..65065793 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/IndexExpression.cs @@ -1,4 +1,5 @@ -using MoonSharp.Interpreter.Execution; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Execution.VM; namespace MoonSharp.Interpreter.Tree.Expressions @@ -74,5 +75,11 @@ public override DynValue Eval(ScriptExecutionContext context) else if (i.IsNilOrNan()) throw new DynamicExpressionException("Attempt to index with nil or nan key."); return b.Table.Get(i) ?? DynValue.Nil; } + + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/LiteralExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/LiteralExpression.cs index 9580c60c..d9a49692 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/LiteralExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/LiteralExpression.cs @@ -1,4 +1,5 @@ -using MoonSharp.Interpreter.Execution; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions { @@ -61,5 +62,11 @@ public override DynValue Eval(ScriptExecutionContext context) { return m_Value; } + + public override bool EvalLiteral(out DynValue dv) + { + dv = m_Value; + return true; + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/SymbolRefExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/SymbolRefExpression.cs index 722c1d60..afba41f0 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/SymbolRefExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/SymbolRefExpression.cs @@ -1,4 +1,5 @@ -using MoonSharp.Interpreter.Execution; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions { @@ -58,6 +59,12 @@ public override DynValue Eval(ScriptExecutionContext context) return context.EvaluateSymbolByName(m_VarName); } + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } + public override SymbolRef FindDynamic(ScriptExecutionContext context) { return context.FindSymbolByName(m_VarName); diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/TableConstructor.cs b/src/MoonSharp.Interpreter/Tree/Expressions/TableConstructor.cs index be4093ca..bf7fd47a 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/TableConstructor.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/TableConstructor.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Execution; namespace MoonSharp.Interpreter.Tree.Expressions @@ -131,5 +132,11 @@ public override DynValue Eval(ScriptExecutionContext context) return tval; } + + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + return false; + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs b/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs index ec763585..5fed5b45 100644 --- a/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs +++ b/src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs @@ -1,4 +1,6 @@ -using MoonSharp.Interpreter.Execution; +using System; +using MoonSharp.Interpreter.DataStructs; +using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Execution.VM; namespace MoonSharp.Interpreter.Tree.Expressions @@ -62,5 +64,31 @@ public override DynValue Eval(ScriptExecutionContext context) throw new DynamicExpressionException("Unexpected unary operator '{0}'", m_OpText); } } + + public override bool EvalLiteral(out DynValue dv) + { + dv = null; + if (!m_Exp.EvalLiteral(out var v)) + { + return false; + } + switch (m_OpText) + { + case "not": + dv = DynValue.NewBoolean(!v.CastToBool()); + return true; + case "#": + return false; + case "-": + double? d = v.CastToNumber(); + if (d.HasValue) + { + dv = DynValue.NewNumber(-d.Value); + return true; + } + break; + } + throw new Exception("Invalid literal evaluation"); + } } } diff --git a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs index a82fe67a..5546627f 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/AssignmentStatement.cs @@ -95,7 +95,7 @@ public override void Compile(Execution.VM.ByteCode bc) { foreach (var exp in m_RValues) { - exp.Compile(bc); + exp.CompilePossibleLiteral(bc); } for (int i = 0; i < m_LValues.Count; i++) diff --git a/src/MoonSharp.Interpreter/Tree/Statements/ForLoopStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/ForLoopStatement.cs index 614c50b3..64454f3b 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/ForLoopStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/ForLoopStatement.cs @@ -60,11 +60,11 @@ public override void Compile(ByteCode bc) bc.LoopTracker.Loops.Push(L); - m_End.Compile(bc); + m_End.CompilePossibleLiteral(bc); bc.Emit_ToNum(3); m_Step.Compile(bc); bc.Emit_ToNum(2); - m_Start.Compile(bc); + m_Start.CompilePossibleLiteral(bc); bc.Emit_ToNum(1); int start = bc.GetJumpPointForNextInstruction(); diff --git a/src/MoonSharp.Interpreter/Tree/Statements/IfStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/IfStatement.cs index 5f5dda5a..8433caed 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/IfStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/IfStatement.cs @@ -83,7 +83,7 @@ public override void Compile(Execution.VM.ByteCode bc) if (lastIfJmp != null) lastIfJmp.NumVal = bc.GetJumpPointForNextInstruction(); - ifblock.Exp.Compile(bc); + ifblock.Exp.CompilePossibleLiteral(bc); lastIfJmp = bc.Emit_Jump(OpCode.Jf, -1); bc.Emit_Enter(ifblock.StackFrame); ifblock.Block.Compile(bc); diff --git a/src/MoonSharp.Interpreter/Tree/Statements/ReturnStatement.cs b/src/MoonSharp.Interpreter/Tree/Statements/ReturnStatement.cs index e0ab2f98..b24262e3 100644 --- a/src/MoonSharp.Interpreter/Tree/Statements/ReturnStatement.cs +++ b/src/MoonSharp.Interpreter/Tree/Statements/ReturnStatement.cs @@ -51,7 +51,7 @@ public override void Compile(Execution.VM.ByteCode bc) { if (m_Expression != null) { - m_Expression.Compile(bc); + m_Expression.CompilePossibleLiteral(bc); bc.Emit_Ret(1); } else