Generic For Loops

This commit is contained in:
Deukhoofd 2018-11-23 18:18:07 +01:00
parent 2db4d0607e
commit 638394d25b
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
38 changed files with 530 additions and 327 deletions

View File

@ -1,8 +0,0 @@
namespace Upsilon.BaseTypes.LuaTypeInterfaces
{
public interface IIterable
{
bool Next(out LuaType key, out LuaType next);
void Reset();
}
}

View File

@ -1,11 +0,0 @@
using Upsilon.Evaluator;
using Upsilon.Text;
namespace Upsilon.BaseTypes
{
internal interface IIndexable
{
LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope);
void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value);
}
}

View File

@ -1,99 +0,0 @@
namespace Upsilon.BaseTypes.Number
{
internal abstract class Number : LuaType
{
protected abstract bool IsFloat { get; }
public override Type Type => Type.Number;
#region Binary Operators
public static Number operator + (Number a, Number b)
{
if (!a.IsFloat && !b.IsFloat)
return new NumberLong(((NumberLong) a).Value + ((NumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new NumberDouble(((NumberDouble) a).Value + ((NumberDouble) b).Value);
if (a.IsFloat)
return new NumberDouble(((NumberDouble) a).Value + ((NumberLong) b).Value);
return new NumberDouble(((NumberLong) a).Value + ((NumberDouble) b).Value);
}
public static Number operator - (Number a, Number b)
{
if (!a.IsFloat && !b.IsFloat)
return new NumberLong(((NumberLong) a).Value - ((NumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new NumberDouble(((NumberDouble) a).Value - ((NumberDouble) b).Value);
if (a.IsFloat)
return new NumberDouble(((NumberDouble) a).Value - ((NumberLong) b).Value);
return new NumberDouble(((NumberLong) a).Value - ((NumberDouble) b).Value);
}
public static Number operator * (Number a, Number b)
{
if (!a.IsFloat && !b.IsFloat)
return new NumberLong(((NumberLong) a).Value * ((NumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new NumberDouble(((NumberDouble) a).Value * ((NumberDouble) b).Value);
if (a.IsFloat)
return new NumberDouble(((NumberDouble) a).Value * ((NumberLong) b).Value);
return new NumberDouble(((NumberLong) a).Value * ((NumberDouble) b).Value);
}
public static Number operator / (Number a, Number b)
{
if (!a.IsFloat && !b.IsFloat)
return new NumberLong(((NumberLong) a).Value / ((NumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new NumberDouble(((NumberDouble) a).Value / ((NumberDouble) b).Value);
if (a.IsFloat)
return new NumberDouble(((NumberDouble) a).Value / ((NumberLong) b).Value);
return new NumberDouble(((NumberLong) a).Value / ((NumberDouble) b).Value);
}
#endregion
public static Number operator - (Number n)
{
if (n.IsFloat)
return new NumberDouble(-((NumberDouble)n).Value);
return new NumberLong(-((NumberLong)n).Value);
}
#region Equality
private bool Equals(Number other)
{
if (!IsFloat && !other.IsFloat)
return ((NumberLong) this).Value.Equals(((NumberLong) other).Value);
if (IsFloat && other.IsFloat)
return ((NumberDouble) this).Value.Equals(((NumberDouble) other).Value);
return false;
}
#pragma warning disable 659
public override bool Equals(object obj)
#pragma warning restore 659
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Number) obj);
}
#endregion
public static explicit operator double(Number n)
{
if (n.IsFloat)
return ((NumberDouble) n);
return ((NumberLong) n).Value;
}
public static explicit operator long(Number n)
{
if (n.IsFloat)
return (long)((NumberDouble) n).Value;
return ((NumberLong) n).Value;
}
}
}

View File

@ -0,0 +1,99 @@
namespace Upsilon.BaseTypes.Number
{
internal abstract class ScriptNumber : ScriptType
{
protected abstract bool IsFloat { get; }
public override Type Type => Type.Number;
#region Binary Operators
public static ScriptNumber operator + (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value + ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value + ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value + ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value + ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator - (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value - ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value - ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value - ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value - ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator * (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value * ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value * ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value * ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value * ((ScriptNumberDouble) b).Value);
}
public static ScriptNumber operator / (ScriptNumber a, ScriptNumber b)
{
if (!a.IsFloat && !b.IsFloat)
return new ScriptNumberLong(((ScriptNumberLong) a).Value / ((ScriptNumberLong) b).Value);
if (a.IsFloat && b.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value / ((ScriptNumberDouble) b).Value);
if (a.IsFloat)
return new ScriptNumberDouble(((ScriptNumberDouble) a).Value / ((ScriptNumberLong) b).Value);
return new ScriptNumberDouble(((ScriptNumberLong) a).Value / ((ScriptNumberDouble) b).Value);
}
#endregion
public static ScriptNumber operator - (ScriptNumber n)
{
if (n.IsFloat)
return new ScriptNumberDouble(-((ScriptNumberDouble)n).Value);
return new ScriptNumberLong(-((ScriptNumberLong)n).Value);
}
#region Equality
private bool Equals(ScriptNumber other)
{
if (!IsFloat && !other.IsFloat)
return ((ScriptNumberLong) this).Value.Equals(((ScriptNumberLong) other).Value);
if (IsFloat && other.IsFloat)
return ((ScriptNumberDouble) this).Value.Equals(((ScriptNumberDouble) other).Value);
return false;
}
#pragma warning disable 659
public override bool Equals(object obj)
#pragma warning restore 659
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ScriptNumber) obj);
}
#endregion
public static explicit operator double(ScriptNumber n)
{
if (n.IsFloat)
return ((ScriptNumberDouble) n);
return ((ScriptNumberLong) n).Value;
}
public static explicit operator long(ScriptNumber n)
{
if (n.IsFloat)
return (long)((ScriptNumberDouble) n).Value;
return ((ScriptNumberLong) n).Value;
}
}
}

View File

@ -2,12 +2,12 @@ using System.Globalization;
namespace Upsilon.BaseTypes.Number namespace Upsilon.BaseTypes.Number
{ {
internal class NumberDouble : Number internal class ScriptNumberDouble : ScriptNumber
{ {
public double Value { get; } public double Value { get; }
protected override bool IsFloat { get; } = true; protected override bool IsFloat { get; } = true;
public NumberDouble(double value) public ScriptNumberDouble(double value)
{ {
Value = value; Value = value;
} }
@ -22,7 +22,7 @@ namespace Upsilon.BaseTypes.Number
return Value.ToString(CultureInfo.InvariantCulture); return Value.ToString(CultureInfo.InvariantCulture);
} }
public static implicit operator double(NumberDouble n) public static implicit operator double(ScriptNumberDouble n)
{ {
return n.Value; return n.Value;
} }

View File

@ -3,12 +3,12 @@ using System.Globalization;
namespace Upsilon.BaseTypes.Number namespace Upsilon.BaseTypes.Number
{ {
internal class NumberLong : Number internal class ScriptNumberLong : ScriptNumber
{ {
public long Value { get; set; } public long Value { get; set; }
protected override bool IsFloat { get; } = false; protected override bool IsFloat { get; } = false;
public NumberLong(long val) public ScriptNumberLong(long val)
{ {
Value = val; Value = val;
} }
@ -23,7 +23,7 @@ namespace Upsilon.BaseTypes.Number
return Value.ToString(CultureInfo.InvariantCulture); return Value.ToString(CultureInfo.InvariantCulture);
} }
public static implicit operator long(NumberLong n) public static implicit operator long(ScriptNumberLong n)
{ {
if (n == null) if (n == null)
return 0; return 0;

View File

@ -1,8 +1,8 @@
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class LuaBoolean : LuaType internal class ScriptBoolean : ScriptType
{ {
public LuaBoolean(bool value) public ScriptBoolean(bool value)
{ {
Value = value; Value = value;
} }
@ -20,19 +20,19 @@ namespace Upsilon.BaseTypes
public bool Value { get; } public bool Value { get; }
public static implicit operator bool(LuaBoolean b) public static implicit operator bool(ScriptBoolean b)
{ {
return b.Value; return b.Value;
} }
public static implicit operator LuaBoolean(bool b) public static implicit operator ScriptBoolean(bool b)
{ {
return new LuaBoolean(b); return new ScriptBoolean(b);
} }
public static LuaBoolean operator ! (LuaBoolean n) public static ScriptBoolean operator ! (ScriptBoolean n)
{ {
return new LuaBoolean(!n.Value); return new ScriptBoolean(!n.Value);
} }
public override string ToString() public override string ToString()

View File

@ -1,14 +1,14 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Upsilon.BaseTypes.LuaTypeInterfaces; using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.BaseTypes.UserData; using Upsilon.BaseTypes.UserData;
using Upsilon.Binder; using Upsilon.Binder;
using Upsilon.Evaluator; using Upsilon.Evaluator;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal abstract class LuaFunction : LuaType internal abstract class ScriptFunction : ScriptType
{ {
public override Type Type => Type.Function; public override Type Type => Type.Function;
public override object ToCSharpObject() public override object ToCSharpObject()
@ -21,16 +21,16 @@ namespace Upsilon.BaseTypes
return null; return null;
} }
public abstract LuaType Run(Diagnostics diagnostics, LuaType[] variables); public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables);
} }
internal class LuaInternalFunction : LuaFunction, IScopeOwner internal class ScriptInternalFunction : ScriptFunction, IScopeOwner
{ {
public BoundBlockStatement Block { get; } public BoundBlockStatement Block { get; }
public ImmutableArray<VariableSymbol> Parameters { get; } public ImmutableArray<VariableSymbol> Parameters { get; }
public EvaluationScope EvaluationScope { get; } public EvaluationScope EvaluationScope { get; }
public LuaInternalFunction(ImmutableArray<VariableSymbol> parameters, BoundBlockStatement block, public ScriptInternalFunction(ImmutableArray<VariableSymbol> parameters, BoundBlockStatement block,
EvaluationScope evaluationScope) EvaluationScope evaluationScope)
{ {
Parameters = parameters; Parameters = parameters;
@ -38,22 +38,22 @@ namespace Upsilon.BaseTypes
EvaluationScope = evaluationScope; EvaluationScope = evaluationScope;
} }
public override LuaType Run(Diagnostics diagnostics, LuaType[] variables) public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables)
{ {
var innerEvaluator = new Evaluator.Evaluator(diagnostics, EvaluationScope); var innerEvaluator = new Evaluator.Evaluator(diagnostics, EvaluationScope);
for (var i = 0; i < Parameters.Length; i++) for (var i = 0; i < Parameters.Length; i++)
{ {
var parameterVariable = Parameters[i]; var parameterVariable = Parameters[i];
var parameterValue = variables[i]; var parameterValue = variables[i];
innerEvaluator.Scope.Set(parameterVariable, parameterValue); innerEvaluator.Scope.Set(parameterVariable, parameterValue, true);
} }
return innerEvaluator.EvaluateNode(Block); return innerEvaluator.EvaluateNode(Block);
} }
} }
internal class LuaMethodInfoFunction : LuaFunction internal class ScriptMethodInfoFunction : ScriptFunction
{ {
public LuaMethodInfoFunction(UserDataMethod method, object o) public ScriptMethodInfoFunction(UserDataMethod method, object o)
{ {
_method = method; _method = method;
_object = o; _object = o;
@ -62,7 +62,7 @@ namespace Upsilon.BaseTypes
private readonly UserDataMethod _method; private readonly UserDataMethod _method;
private readonly object _object; private readonly object _object;
public override LuaType Run(Diagnostics diagnostics, LuaType[] variables) public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables)
{ {
var types = variables.Select(x => x.GetCSharpType()); var types = variables.Select(x => x.GetCSharpType());
var method = _method.GetMethod(types.ToArray()); var method = _method.GetMethod(types.ToArray());

View File

@ -1,6 +1,6 @@
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class LuaNull : LuaType internal class ScriptNull : ScriptType
{ {
public override Type Type => Type.Nil; public override Type Type => Type.Nil;
public override object ToCSharpObject() public override object ToCSharpObject()

View File

@ -1,13 +1,14 @@
using System; using System;
using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class LuaString : LuaType, IIndexable internal class ScriptString : ScriptType, IIndexable
{ {
public LuaString(string value) public ScriptString(string value)
{ {
Value = value; Value = value;
} }
@ -28,7 +29,7 @@ namespace Upsilon.BaseTypes
{ {
if (obj == null) if (obj == null)
return false; return false;
if (!(obj is LuaString s)) if (!(obj is ScriptString s))
return false; return false;
return Equals(s); return Equals(s);
} }
@ -38,45 +39,45 @@ namespace Upsilon.BaseTypes
return (Value != null ? Value.GetHashCode() : 0); return (Value != null ? Value.GetHashCode() : 0);
} }
private bool Equals(LuaString s) private bool Equals(ScriptString s)
{ {
return s != null && string.Equals(s.Value, Value); return s != null && string.Equals(s.Value, Value);
} }
public static LuaString operator +(LuaString a, LuaType b) public static ScriptString operator +(ScriptString a, ScriptType b)
{ {
switch (b) switch (b)
{ {
case LuaString s: case ScriptString s:
return a + s; return a + s;
case LuaBoolean bl: case ScriptBoolean bl:
return a + bl; return a + bl;
case NumberLong l: case ScriptNumberLong l:
return a + l; return a + l;
case NumberDouble d: case ScriptNumberDouble d:
return a + d; return a + d;
} }
throw new ArgumentException($"Adding Type '{b.Type}' to a LuaString is not supported."); throw new ArgumentException($"Adding Type '{b.Type}' to a LuaString is not supported.");
} }
public static LuaString operator +(LuaString a, LuaString b) public static ScriptString operator +(ScriptString a, ScriptString b)
{ {
return new LuaString(a.Value + b.Value); return new ScriptString(a.Value + b.Value);
} }
public static LuaString operator +(LuaString a, LuaBoolean b) public static ScriptString operator +(ScriptString a, ScriptBoolean b)
{ {
return new LuaString(a.Value + b.Value); return new ScriptString(a.Value + b.Value);
} }
public static LuaString operator +(LuaString a, NumberLong b) public static ScriptString operator +(ScriptString a, ScriptNumberLong b)
{ {
return new LuaString(a.Value + b.Value); return new ScriptString(a.Value + b.Value);
} }
public static LuaString operator +(LuaString a, NumberDouble b) public static ScriptString operator +(ScriptString a, ScriptNumberDouble b)
{ {
return new LuaString(a.Value + b.Value); return new ScriptString(a.Value + b.Value);
} }
public override string ToString() public override string ToString()
@ -84,27 +85,27 @@ namespace Upsilon.BaseTypes
return Value; return Value;
} }
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
int i; int i;
if (index.Type == Type.String) if (index.Type == Type.String)
{ {
var str = (LuaString)index; var str = (ScriptString)index;
i = int.Parse(str.Value); i = int.Parse(str.Value);
} }
else if (index.Type == Type.Number) else if (index.Type == Type.Number)
{ {
var ind = (Number.NumberLong) index; var ind = (Number.ScriptNumberLong) index;
i = (int) ind.Value; i = (int) ind.Value;
} }
else else
{ {
return null; return null;
} }
return new LuaString(Value[i - 1].ToString()); return new ScriptString(Value[i - 1].ToString());
} }
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -1,17 +1,17 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Upsilon.BaseTypes.LuaTypeInterfaces; using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Binder; using Upsilon.Binder;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class LuaTable : LuaType, IIndexable, IScopeOwner, IIterable internal class ScriptTable : ScriptType, IIndexable, IScopeOwner, IIterable
{ {
public EvaluationScope EvaluationScope { get; } public EvaluationScope EvaluationScope { get; }
public LuaTable(EvaluationScope scope) public ScriptTable(EvaluationScope scope)
{ {
EvaluationScope = scope; EvaluationScope = scope;
} }
@ -27,7 +27,7 @@ namespace Upsilon.BaseTypes
return typeof(Dictionary<string, object>); return typeof(Dictionary<string, object>);
} }
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
var s = index.ToString(); var s = index.ToString();
if (EvaluationScope.TryGet(s, out var o)) if (EvaluationScope.TryGet(s, out var o))
@ -35,36 +35,26 @@ namespace Upsilon.BaseTypes
return o; return o;
} }
diagnostics.LogError("Cannot find member 's' on Table", span); diagnostics.LogError("Cannot find member 's' on Table", span);
return new LuaNull(); return new ScriptNull();
} }
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
var s = index.ToString(); var s = index.ToString();
EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value); EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value, true);
} }
public IEnumerator<(string Key, ScriptType value)> GetEnumerator()
private IEnumerator<KeyValuePair<string, LuaType>> _enumerator;
public bool Next(out LuaType key, out LuaType next)
{ {
if (_enumerator == null) _enumerator = EvaluationScope.Variables.GetEnumerator(); return Enumerator();
if (_enumerator.MoveNext()) }
private IEnumerator<(string Key, ScriptType value)> Enumerator()
{
foreach (var variable in EvaluationScope.Variables)
{ {
key = _enumerator.Current.Key.ToLuaType(); yield return (variable.Key, variable.Value);
next = _enumerator.Current.Value;
return true;
} }
key = null;
next = null;
Reset();
return false;
}
public void Reset()
{
_enumerator = null;
} }
} }
} }

View File

@ -1,6 +1,6 @@
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
public abstract class LuaType public abstract class ScriptType
{ {
public abstract Type Type { get; } public abstract Type Type { get; }
public abstract object ToCSharpObject(); public abstract object ToCSharpObject();

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Upsilon.BaseTypes.ScriptTypeInterfaces
{
internal interface IIterable
{
IEnumerator<(string Key, ScriptType value)> GetEnumerator();
}
}

View File

@ -0,0 +1,13 @@
using System.Collections;
using System.Collections.Generic;
using Upsilon.Evaluator;
using Upsilon.Text;
namespace Upsilon.BaseTypes.ScriptTypeInterfaces
{
internal interface IIndexable
{
ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope);
void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value);
}
}

View File

@ -1,6 +1,6 @@
using Upsilon.Evaluator; using Upsilon.Evaluator;
namespace Upsilon.BaseTypes.LuaTypeInterfaces namespace Upsilon.BaseTypes.ScriptTypeInterfaces
{ {
internal interface IScopeOwner internal interface IScopeOwner
{ {

View File

@ -1,32 +1,33 @@
using System.Collections.Generic; using System.Collections.Generic;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
internal class SimpleLuaTable : LuaType, IIndexable internal class SimpleScriptTable : ScriptType, IIndexable
{ {
private readonly IList<LuaType> _objects; private readonly IList<ScriptType> _objects;
public SimpleLuaTable(IList<LuaType> objects) public SimpleScriptTable(IList<ScriptType> objects)
{ {
_objects = objects; _objects = objects;
} }
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
int i; int i;
switch (index.Type) switch (index.Type)
{ {
case Type.String: case Type.String:
{ {
var str = (LuaString)index; var str = (ScriptString)index;
i = int.Parse(str.Value) - 1; i = int.Parse(str.Value) - 1;
break; break;
} }
case Type.Number: case Type.Number:
{ {
var ind = (Number.NumberLong) index; var ind = (Number.ScriptNumberLong) index;
i = (int) ind.Value - 1; i = (int) ind.Value - 1;
break; break;
} }
@ -37,7 +38,7 @@ namespace Upsilon.BaseTypes
return _objects[i]; return _objects[i];
} }
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }

View File

@ -10,6 +10,6 @@ namespace Upsilon.BaseTypes
Function, Function,
UserData, UserData,
Thread, Thread,
Table Table,
} }
} }

View File

@ -6,31 +6,31 @@ namespace Upsilon.BaseTypes
{ {
internal static class TypeConversion internal static class TypeConversion
{ {
public static LuaType ToLuaType(this object o) public static ScriptType ToLuaType(this object o)
{ {
if (o is LuaType type) return type; if (o is ScriptType type) return type;
switch (o) switch (o)
{ {
case bool b: case bool b:
return new LuaBoolean(b); return new ScriptBoolean(b);
case int i: case int i:
return new NumberLong(i); return new ScriptNumberLong(i);
case long i: case long i:
return new NumberLong(i); return new ScriptNumberLong(i);
case float f: case float f:
return new NumberDouble(f); return new ScriptNumberDouble(f);
case double f: case double f:
return new NumberDouble(f); return new ScriptNumberDouble(f);
case string s: case string s:
return new LuaString(s); return new ScriptString(s);
case null: case null:
return new LuaNull(); return new ScriptNull();
default: default:
return ConvertUserData(o); return ConvertUserData(o);
} }
} }
private static LuaType ConvertUserData(object o) private static ScriptType ConvertUserData(object o)
{ {
if (o is IList ls) if (o is IList ls)
{ {

View File

@ -4,7 +4,7 @@ using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class DictionaryUserData : LuaType, IUserData internal class DictionaryUserData : ScriptType, IUserData
{ {
public IDictionary Dictionary { get; } public IDictionary Dictionary { get; }
@ -13,7 +13,7 @@ namespace Upsilon.BaseTypes.UserData
Dictionary = dictionary; Dictionary = dictionary;
} }
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
var key = index.ToCSharpObject(); var key = index.ToCSharpObject();
if (Dictionary.Contains(key)) if (Dictionary.Contains(key))
@ -21,10 +21,10 @@ namespace Upsilon.BaseTypes.UserData
return Dictionary[key].ToLuaType(); return Dictionary[key].ToLuaType();
} }
//TODO: log error //TODO: log error
return new LuaNull(); return new ScriptNull();
} }
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
var key = index.ToCSharpObject(); var key = index.ToCSharpObject();
if (Dictionary.Contains(key)) if (Dictionary.Contains(key))

View File

@ -3,7 +3,7 @@ using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class GenericUserData : LuaType, IUserData internal class GenericUserData : ScriptType, IUserData
{ {
public GenericUserData(object dictionary) public GenericUserData(object dictionary)
{ {
@ -25,7 +25,7 @@ namespace Upsilon.BaseTypes.UserData
return Value.GetType(); return Value.GetType();
} }
public virtual LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public virtual ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
var s = index.ToCSharpObject().ToString(); var s = index.ToCSharpObject().ToString();
var (type, failed, error) = _typeInfo.Get(Value, s); var (type, failed, error) = _typeInfo.Get(Value, s);
@ -36,7 +36,7 @@ namespace Upsilon.BaseTypes.UserData
return type; return type;
} }
public virtual void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public virtual void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
var s = index.ToCSharpObject().ToString(); var s = index.ToCSharpObject().ToString();
var (failed, error) = _typeInfo.Set(Value, s, value); var (failed, error) = _typeInfo.Set(Value, s, value);
@ -46,12 +46,12 @@ namespace Upsilon.BaseTypes.UserData
} }
} }
public (LuaType Type, bool Failed) BinaryOperator(LuaType par1, OperatorType op, LuaType par2) public (ScriptType Type, bool Failed) BinaryOperator(ScriptType par1, OperatorType op, ScriptType par2)
{ {
return _typeInfo.BinaryOperator(Value, par1, op, par2); return _typeInfo.BinaryOperator(Value, par1, op, par2);
} }
public (LuaType Type, bool Failed) UnaryOperator(LuaType par1, OperatorType op) public (ScriptType Type, bool Failed) UnaryOperator(ScriptType par1, OperatorType op)
{ {
return _typeInfo.UnaryOperator(Value, par1, op); return _typeInfo.UnaryOperator(Value, par1, op);
} }

View File

@ -1,3 +1,5 @@
using Upsilon.BaseTypes.ScriptTypeInterfaces;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal interface IUserData : IIndexable internal interface IUserData : IIndexable

View File

@ -1,10 +1,12 @@
using System.Collections; using System.Collections;
using System.Collections.Generic;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Text; using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
internal class ListUserData : LuaType, IUserData internal class ListUserData : ScriptType, IUserData, IIterable
{ {
private IList List { get; } private IList List { get; }
@ -13,17 +15,17 @@ namespace Upsilon.BaseTypes.UserData
List = list; List = list;
} }
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope) public ScriptType Get(Diagnostics diagnostics, TextSpan span, ScriptType index, EvaluationScope scope)
{ {
int i; int i;
if (index.Type == Type.String) if (index.Type == Type.String)
{ {
var str = (LuaString)index; var str = (ScriptString)index;
i = int.Parse(str.Value) - 1; i = int.Parse(str.Value) - 1;
} }
else if (index.Type == Type.Number) else if (index.Type == Type.Number)
{ {
var ind = (Number.NumberLong) index; var ind = (Number.ScriptNumberLong) index;
i = (int) ind.Value - 1; i = (int) ind.Value - 1;
} }
else else
@ -33,7 +35,7 @@ namespace Upsilon.BaseTypes.UserData
return List[i].ToLuaType(); return List[i].ToLuaType();
} }
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value) public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
@ -48,5 +50,10 @@ namespace Upsilon.BaseTypes.UserData
{ {
return List.GetType(); return List.GetType();
} }
public IEnumerator<(string Key, ScriptType value)> GetEnumerator()
{
throw new System.NotImplementedException();
}
} }
} }

View File

@ -22,11 +22,11 @@ namespace Upsilon.BaseTypes.UserData
{ {
public UserDataMethodParameter(ParameterInfo info) public UserDataMethodParameter(ParameterInfo info)
{ {
TypeHash = info.ParameterType.GetHashCode(); Type = info.ParameterType;
IsOptional = info.IsOptional; IsOptional = info.IsOptional;
} }
public int TypeHash { get; } public System.Type Type { get; }
public bool IsOptional { get; } public bool IsOptional { get; }
} }
@ -62,8 +62,9 @@ namespace Upsilon.BaseTypes.UserData
valid = false; valid = false;
break; break;
} }
var parameterHash = parameterTypes[index].GetHashCode(); var parameter = parameterTypes[index];
if (userDataMethodParameter.TypeHash != parameterHash) if (userDataMethodParameter.Type != parameter &&
!userDataMethodParameter.Type.IsAssignableFrom(parameter))
{ {
valid = false; valid = false;
break; break;

View File

@ -33,7 +33,7 @@ namespace Upsilon.BaseTypes.UserData
private Dictionary<string, UserDataMethod> Methods { get; } private Dictionary<string, UserDataMethod> Methods { get; }
private UserDataTypeOperators OperatorHandler { get; } private UserDataTypeOperators OperatorHandler { get; }
public (LuaType Type, bool Failed, string Error) Get(object value, string member) public (ScriptType Type, bool Failed, string Error) Get(object value, string member)
{ {
if (value.GetType() != Type) if (value.GetType() != Type)
return (null, true, "Invalid Type"); return (null, true, "Invalid Type");
@ -48,13 +48,13 @@ namespace Upsilon.BaseTypes.UserData
} }
if (Methods.TryGetValue(member, out var method)) if (Methods.TryGetValue(member, out var method))
{ {
return (new LuaMethodInfoFunction(method, value), false, null); return (new ScriptMethodInfoFunction(method, value), false, null);
} }
return (null, true, $"Can't find public member '{member}' on type '{Type}'."); return (null, true, $"Can't find public member '{member}' on type '{Type}'.");
} }
public (bool Failed, string Error) Set(object value, string member, LuaType newValue) public (bool Failed, string Error) Set(object value, string member, ScriptType newValue)
{ {
member = member.ToLowerInvariant(); member = member.ToLowerInvariant();
if (value.GetType() != Type) if (value.GetType() != Type)
@ -77,22 +77,22 @@ namespace Upsilon.BaseTypes.UserData
return (true, $"Cannot find member '{member}' on type '{Type}'"); return (true, $"Cannot find member '{member}' on type '{Type}'");
} }
public (LuaType Type, bool Failed) BinaryOperator(object value, LuaType par1, OperatorType op, LuaType par2) public (ScriptType Type, bool Failed) BinaryOperator(object value, ScriptType par1, OperatorType op, ScriptType par2)
{ {
var method = OperatorHandler.GetBinaryOperator(op, par1.GetCSharpType(), par2.GetCSharpType()); var method = OperatorHandler.GetBinaryOperator(op, par1.GetCSharpType(), par2.GetCSharpType());
if (method == null) if (method == null)
{ {
return (new LuaNull(), true); return (new ScriptNull(), true);
} }
return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToLuaType(), false); return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToLuaType(), false);
} }
public (LuaType Type, bool Failed) UnaryOperator(object value, LuaType par1, OperatorType op) public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op)
{ {
var method = OperatorHandler.GetUnaryOperator(op, par1.GetCSharpType()); var method = OperatorHandler.GetUnaryOperator(op, par1.GetCSharpType());
if (method == null) if (method == null)
{ {
return (new LuaNull(), true); return (new ScriptNull(), true);
} }
return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToLuaType(), false); return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToLuaType(), false);

View File

@ -70,6 +70,9 @@ namespace Upsilon.Binder
return BindMultiAssignmentStatement((MultiAssignmentStatementSyntax) s); return BindMultiAssignmentStatement((MultiAssignmentStatementSyntax) s);
case SyntaxKind.NumericForStatement: case SyntaxKind.NumericForStatement:
return BindNumericForStatement((NumericForStatementSyntax) s); return BindNumericForStatement((NumericForStatementSyntax) s);
case SyntaxKind.GenericForStatement:
return BindGenericForStatement((GenericForStatementSyntax) s);
case SyntaxKind.BreakStatement: case SyntaxKind.BreakStatement:
return new BoundBreakStatement(); return new BoundBreakStatement();
} }
@ -140,23 +143,23 @@ namespace Upsilon.Binder
private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e) private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e)
{ {
var value = e.Value; var value = e.Value;
LuaType outValue = null; ScriptType outValue = null;
switch (value) switch (value)
{ {
case double d: case double d:
outValue = new NumberDouble(d); outValue = new ScriptNumberDouble(d);
break; break;
case long l: case long l:
outValue = new NumberLong(l); outValue = new ScriptNumberLong(l);
break; break;
case bool b: case bool b:
outValue = new LuaBoolean(b); outValue = new ScriptBoolean(b);
break; break;
case string s: case string s:
outValue = new LuaString(s); outValue = new ScriptString(s);
break; break;
case null: case null:
outValue = new LuaNull(); outValue = new ScriptNull();
break; break;
default: default:
@ -221,7 +224,7 @@ namespace Upsilon.Binder
if (!Scope.TryGetVariable(name, true, out var variable)) if (!Scope.TryGetVariable(name, true, out var variable))
{ {
_diagnostics.LogUnknownVariable(e.Identifier.Span, name); _diagnostics.LogUnknownVariable(e.Identifier.Span, name);
return new BoundLiteralExpression(new LuaNull()); return new BoundLiteralExpression(new ScriptNull());
} }
return new BoundVariableExpression(variable); return new BoundVariableExpression(variable);
@ -301,7 +304,7 @@ namespace Upsilon.Binder
} }
return new BoundExpressionStatement(new BoundLiteralExpression(new LuaNull())); return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull()));
} }
private BoundStatement BindMultiAssignmentStatement(MultiAssignmentStatementSyntax s) private BoundStatement BindMultiAssignmentStatement(MultiAssignmentStatementSyntax s)
@ -430,7 +433,7 @@ namespace Upsilon.Binder
else else
{ {
_diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span); _diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span);
return new BoundExpressionStatement(new BoundLiteralExpression(new LuaNull())); return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull()));
} }
} }
} }
@ -474,7 +477,7 @@ namespace Upsilon.Binder
if (index.Type != Type.Number && index.Type != Type.String && index.Type != Type.Unknown) if (index.Type != Type.Number && index.Type != Type.String && index.Type != Type.Unknown)
{ {
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span); _diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
return new BoundLiteralExpression(new LuaNull()); return new BoundLiteralExpression(new ScriptNull());
} }
switch (expression.Type) switch (expression.Type)
{ {
@ -486,7 +489,7 @@ namespace Upsilon.Binder
return new BoundIndexExpression(expression, index, Type.String); return new BoundIndexExpression(expression, index, Type.String);
default: default:
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span); _diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
return new BoundLiteralExpression(new LuaNull()); return new BoundLiteralExpression(new ScriptNull());
} }
} }
@ -504,7 +507,7 @@ namespace Upsilon.Binder
return new BoundFullStopIndexExpression(expression, index); return new BoundFullStopIndexExpression(expression, index);
default: default:
_diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span); _diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span);
return new BoundLiteralExpression(new LuaNull()); return new BoundLiteralExpression(new ScriptNull());
} }
} }
@ -526,14 +529,30 @@ namespace Upsilon.Binder
Scope = new BoundScope(Scope); Scope = new BoundScope(Scope);
var variable = new VariableSymbol(variableName, Type.Number, true); var variable = new VariableSymbol(variableName, Type.Number, true);
Scope.SetVariable(variable); Scope.SetVariable(variable);
var boundStart = BindExpression(e.StartExpression); var boundStart = BindExpression(e.StartExpression);
var boundStop = BindExpression(e.StopExpression); var boundStop = BindExpression(e.StopExpression);
BoundExpression boundStep = null; BoundExpression boundStep = null;
if (e.StepExpression != null) if (e.StepExpression != null)
boundStep = BindExpression(e.StepExpression); boundStep = BindExpression(e.StepExpression);
var block = BindBlockStatement((BlockStatementSyntax) e.Block); var block = BindBlockStatement((BlockStatementSyntax) e.Block);
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
return new BoundNumericForStatement(variable, boundStart, boundStop, boundStep, (BoundBlockStatement) block); return new BoundNumericForStatement(variable, boundStart, boundStop, boundStep, (BoundBlockStatement) block);
} }
private BoundStatement BindGenericForStatement(GenericForStatementSyntax e)
{
Scope = new BoundScope(Scope);
var array = ImmutableArray.CreateBuilder<VariableSymbol>();
foreach (var variableIdentifier in e.Variables)
{
var variable = new VariableSymbol(variableIdentifier.Name, Type.Unknown, true);
Scope.SetVariable(variable);
array.Add(variable);
}
var boundEnumerableExpression = BindExpression(e.EnumerableExpression);
var block = BindBlockStatement(e.Block);
return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block);
}
} }
} }

View File

@ -4,13 +4,13 @@ namespace Upsilon.Binder
{ {
internal class BoundLiteralExpression : BoundExpression internal class BoundLiteralExpression : BoundExpression
{ {
public BoundLiteralExpression(LuaType value) public BoundLiteralExpression(ScriptType value)
{ {
Value = value; Value = value;
} }
public override BoundKind Kind => BoundKind.BoundLiteralExpression; public override BoundKind Kind => BoundKind.BoundLiteralExpression;
public override Type Type => Value.Type; public override Type Type => Value.Type;
public LuaType Value { get; } public ScriptType Value { get; }
} }
} }

View File

@ -26,6 +26,7 @@ namespace Upsilon.Binder
BoundFullstopIndexExpression, BoundFullstopIndexExpression,
BoundMultiAssignmentStatement, BoundMultiAssignmentStatement,
BoundNumericForStatement, BoundNumericForStatement,
BoundBreakStatement BoundGenericForStatement,
BoundBreakStatement,
} }
} }

View File

@ -0,0 +1,21 @@
using System.Collections.Immutable;
namespace Upsilon.Binder
{
public class BoundGenericForStatement : BoundStatement
{
public ImmutableArray<VariableSymbol> Variables { get; }
public BoundExpression BoundEnumerableExpression { get; }
public BoundStatement Block { get; }
public BoundGenericForStatement(ImmutableArray<VariableSymbol> variables,
BoundExpression boundEnumerableExpression, BoundStatement block)
{
Variables = variables;
BoundEnumerableExpression = boundEnumerableExpression;
Block = block;
}
public override BoundKind Kind => BoundKind.BoundGenericForStatement;
}
}

View File

@ -9,32 +9,32 @@ namespace Upsilon.Evaluator
private readonly EvaluationScope _parentScope; private readonly EvaluationScope _parentScope;
private EvaluationScope _getOnlyParentScope; private EvaluationScope _getOnlyParentScope;
public readonly Dictionary<string, LuaType> Variables; public readonly Dictionary<string, ScriptType> Variables;
private readonly Dictionary<string, LuaType> _localVariables; private readonly Dictionary<string, ScriptType> _localVariables;
internal EvaluationScope(EvaluationScope parentScope) internal EvaluationScope(EvaluationScope parentScope)
{ {
_parentScope = parentScope; _parentScope = parentScope;
Variables = new Dictionary<string, LuaType>(); Variables = new Dictionary<string, ScriptType>();
_localVariables = new Dictionary<string, LuaType>(); _localVariables = new Dictionary<string, ScriptType>();
} }
internal EvaluationScope(Dictionary<string, LuaType> vars) internal EvaluationScope(Dictionary<string, ScriptType> vars)
{ {
Variables = vars; Variables = vars;
_localVariables = new Dictionary<string, LuaType>(); _localVariables = new Dictionary<string, ScriptType>();
} }
internal static EvaluationScope CreateWithGetOnlyParent(EvaluationScope parent) internal static EvaluationScope CreateWithGetOnlyParent(EvaluationScope parent)
{ {
var scope = new EvaluationScope(new Dictionary<string, LuaType>()) {_getOnlyParentScope = parent}; var scope = new EvaluationScope(new Dictionary<string, ScriptType>()) {_getOnlyParentScope = parent};
return scope; return scope;
} }
public void Set(VariableSymbol symbol, LuaType obj) public void Set(VariableSymbol symbol, ScriptType obj, bool createNew)
{ {
if (symbol.Local) if (symbol.Local && createNew)
{ {
if (_localVariables.ContainsKey(symbol.Name)) if (_localVariables.ContainsKey(symbol.Name))
{ {
@ -51,6 +51,14 @@ namespace Upsilon.Evaluator
{ {
Variables[symbol.Name] = obj; Variables[symbol.Name] = obj;
} }
else if (_localVariables.ContainsKey(symbol.Name))
{
_localVariables[symbol.Name] = obj;
}
else if (_parentScope != null && _parentScope.TryGet(symbol.Name, out _))
{
_parentScope.Set(symbol, obj, false);
}
else else
{ {
Variables.Add(symbol.Name, obj); Variables.Add(symbol.Name, obj);
@ -59,17 +67,17 @@ namespace Upsilon.Evaluator
} }
} }
public void SetGlobal(VariableSymbol symbol, LuaType obj) public void SetGlobal(VariableSymbol symbol, ScriptType obj)
{ {
if (_parentScope != null) if (_parentScope != null)
_parentScope.SetGlobal(symbol, obj); _parentScope.SetGlobal(symbol, obj);
else else
{ {
Set(symbol, obj); Set(symbol, obj, true);
} }
} }
public bool TryGet(VariableSymbol symbol, out LuaType obj) public bool TryGet(VariableSymbol symbol, out ScriptType obj)
{ {
if (_localVariables.TryGetValue(symbol.Name, out obj)) if (_localVariables.TryGetValue(symbol.Name, out obj))
return true; return true;
@ -84,7 +92,7 @@ namespace Upsilon.Evaluator
return false; return false;
} }
public bool TryGet(string variable, out LuaType obj) public bool TryGet(string variable, out ScriptType obj)
{ {
if (_localVariables.TryGetValue(variable, out obj)) if (_localVariables.TryGetValue(variable, out obj))
return true; return true;

View File

@ -2,8 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.BaseTypes.LuaTypeInterfaces;
using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.BaseTypes.UserData; using Upsilon.BaseTypes.UserData;
using Upsilon.Binder; using Upsilon.Binder;
using Type = Upsilon.BaseTypes.Type; using Type = Upsilon.BaseTypes.Type;
@ -13,13 +13,13 @@ namespace Upsilon.Evaluator
internal class Evaluator internal class Evaluator
{ {
private Diagnostics _diagnostics; private Diagnostics _diagnostics;
private LuaType _lastValue; private ScriptType _lastValue;
private LuaType _returnValue; private ScriptType _returnValue;
internal EvaluationScope Scope { get; private set; } internal EvaluationScope Scope { get; private set; }
private bool HasReturned { get; set; } private bool HasReturned { get; set; }
private bool HasBroken { get; set; } private bool HasBroken { get; set; }
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables) internal Evaluator(Diagnostics diagnostics, Dictionary<string, ScriptType> variables)
{ {
_diagnostics = diagnostics; _diagnostics = diagnostics;
Scope = new EvaluationScope(variables); Scope = new EvaluationScope(variables);
@ -38,7 +38,7 @@ namespace Upsilon.Evaluator
return new Evaluator {_diagnostics = diagnostics, Scope = scope}; return new Evaluator {_diagnostics = diagnostics, Scope = scope};
} }
public LuaType Evaluate(BoundScript e) public ScriptType Evaluate(BoundScript e)
{ {
EvaluateNode(e.Statement); EvaluateNode(e.Statement);
if (_returnValue == null) if (_returnValue == null)
@ -46,27 +46,27 @@ namespace Upsilon.Evaluator
return _returnValue; return _returnValue;
} }
public LuaType Evaluate(BoundScript e, string functionName, ImmutableArray<LuaType> parameters) public ScriptType Evaluate(BoundScript e, string functionName, ImmutableArray<ScriptType> parameters)
{ {
EvaluateNode(e.Statement); EvaluateNode(e.Statement);
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function) if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
{ {
throw new ArgumentException(($"Function '{functionName}' could not be found")); throw new ArgumentException(($"Function '{functionName}' could not be found"));
} }
var function = (LuaInternalFunction) statement; var function = (ScriptInternalFunction) statement;
var innerEvaluator = new Evaluator(_diagnostics, Scope); var innerEvaluator = new Evaluator(_diagnostics, Scope);
for (var index = 0; index < parameters.Length; index++) for (var index = 0; index < parameters.Length; index++)
{ {
var parameter = parameters[index]; var parameter = parameters[index];
var parameterName = function.Parameters[index]; var parameterName = function.Parameters[index];
innerEvaluator.Scope.Set(parameterName, parameter); innerEvaluator.Scope.Set(parameterName, parameter, true);
} }
var result = innerEvaluator.EvaluateNode(function.Block); var result = innerEvaluator.EvaluateNode(function.Block);
return result; return result;
} }
internal LuaType EvaluateNode(BoundNode b) internal ScriptType EvaluateNode(BoundNode b)
{ {
switch (b.Kind) switch (b.Kind)
{ {
@ -95,6 +95,8 @@ namespace Upsilon.Evaluator
case BoundKind.BoundTableAssigmentStatement: case BoundKind.BoundTableAssigmentStatement:
case BoundKind.BoundMultiAssignmentStatement: case BoundKind.BoundMultiAssignmentStatement:
case BoundKind.BoundNumericForStatement: case BoundKind.BoundNumericForStatement:
case BoundKind.BoundGenericForStatement:
case BoundKind.BoundBreakStatement:
EvaluateStatement((BoundStatement) b); EvaluateStatement((BoundStatement) b);
break; break;
default: default:
@ -136,6 +138,9 @@ namespace Upsilon.Evaluator
case BoundKind.BoundBreakStatement: case BoundKind.BoundBreakStatement:
HasBroken = true; HasBroken = true;
return; return;
case BoundKind.BoundGenericForStatement:
EvaluateGenericForStatement((BoundGenericForStatement) e);
break;
default: default:
EvaluateExpressionStatement((BoundExpressionStatement) e); EvaluateExpressionStatement((BoundExpressionStatement) e);
break; break;
@ -148,7 +153,7 @@ namespace Upsilon.Evaluator
_lastValue = EvaluateExpression(e.Expression); _lastValue = EvaluateExpression(e.Expression);
} }
internal LuaType EvaluateExpression(BoundExpression e) internal ScriptType EvaluateExpression(BoundExpression e)
{ {
switch (e.Kind) switch (e.Kind)
{ {
@ -177,7 +182,7 @@ namespace Upsilon.Evaluator
} }
} }
private LuaType EvaluateUnaryExpression(BoundUnaryExpression e) private ScriptType EvaluateUnaryExpression(BoundUnaryExpression e)
{ {
var operand = EvaluateExpression(e.InExpression); var operand = EvaluateExpression(e.InExpression);
switch (e.Operator.Kind) switch (e.Operator.Kind)
@ -186,7 +191,7 @@ namespace Upsilon.Evaluator
return operand; return operand;
case BoundUnaryOperator.OperatorKind.Negation: case BoundUnaryOperator.OperatorKind.Negation:
if (operand.Type == Type.Number) if (operand.Type == Type.Number)
return -((Number)operand); return -((ScriptNumber)operand);
else if (operand.Type == Type.UserData) else if (operand.Type == Type.UserData)
{ {
var ud = (GenericUserData) operand; var ud = (GenericUserData) operand;
@ -197,7 +202,7 @@ namespace Upsilon.Evaluator
goto default; goto default;
case BoundUnaryOperator.OperatorKind.LogicalNegation: case BoundUnaryOperator.OperatorKind.LogicalNegation:
if (operand.Type == Type.Boolean) if (operand.Type == Type.Boolean)
return !(LuaBoolean) operand; return !(ScriptBoolean) operand;
else if (operand.Type == Type.UserData) else if (operand.Type == Type.UserData)
{ {
var ud = (GenericUserData) operand; var ud = (GenericUserData) operand;
@ -212,7 +217,7 @@ namespace Upsilon.Evaluator
} }
} }
private LuaType EvaluateBinaryExpression(BoundBinaryExpression e) private ScriptType EvaluateBinaryExpression(BoundBinaryExpression e)
{ {
var left = EvaluateExpression(e.LeftExpression); var left = EvaluateExpression(e.LeftExpression);
var right = EvaluateExpression(e.RightExpression); var right = EvaluateExpression(e.RightExpression);
@ -220,10 +225,16 @@ namespace Upsilon.Evaluator
{ {
case BoundBinaryOperator.OperatorKind.Addition: case BoundBinaryOperator.OperatorKind.Addition:
if (left.Type == Type.Number) if (left.Type == Type.Number)
return ((Number)left) + ((Number)right); {
if (right.Type == Type.Number)
{
return ((ScriptNumber)left) + ((ScriptNumber)right);
}
goto default;
}
else if (left.Type == Type.String) else if (left.Type == Type.String)
{ {
return ((LuaString) left) + right; return ((ScriptString) left) + right;
} }
else if (left.Type == Type.UserData) else if (left.Type == Type.UserData)
{ {
@ -236,7 +247,7 @@ namespace Upsilon.Evaluator
case BoundBinaryOperator.OperatorKind.Subtraction: case BoundBinaryOperator.OperatorKind.Subtraction:
if (left.Type == Type.Number) if (left.Type == Type.Number)
{ {
return ((Number)left) - ((Number)right); return ((ScriptNumber)left) - ((ScriptNumber)right);
} }
else if (left.Type == Type.UserData) else if (left.Type == Type.UserData)
{ {
@ -249,7 +260,7 @@ namespace Upsilon.Evaluator
case BoundBinaryOperator.OperatorKind.Multiplication: case BoundBinaryOperator.OperatorKind.Multiplication:
if (left.Type == Type.Number) if (left.Type == Type.Number)
{ {
return ((Number)left) * ((Number)right); return ((ScriptNumber)left) * ((ScriptNumber)right);
} }
else if (left.Type == Type.UserData) else if (left.Type == Type.UserData)
{ {
@ -262,7 +273,7 @@ namespace Upsilon.Evaluator
case BoundBinaryOperator.OperatorKind.Division: case BoundBinaryOperator.OperatorKind.Division:
if (left.Type == Type.Number) if (left.Type == Type.Number)
{ {
return ((Number)left) / ((Number)right); return ((ScriptNumber)left) / ((ScriptNumber)right);
} }
else if (left.Type == Type.UserData) else if (left.Type == Type.UserData)
{ {
@ -273,9 +284,9 @@ namespace Upsilon.Evaluator
} }
goto default; goto default;
case BoundBinaryOperator.OperatorKind.Equality: case BoundBinaryOperator.OperatorKind.Equality:
return new LuaBoolean(Equals(left, right)); return new ScriptBoolean(Equals(left, right));
case BoundBinaryOperator.OperatorKind.Inequality: case BoundBinaryOperator.OperatorKind.Inequality:
return new LuaBoolean(!Equals(left, right)); return new ScriptBoolean(!Equals(left, right));
default: default:
throw new Exception("Invalid Binary Operator: " + e.Operator); throw new Exception("Invalid Binary Operator: " + e.Operator);
} }
@ -286,7 +297,7 @@ namespace Upsilon.Evaluator
var val = EvaluateExpression(e.BoundExpression); var val = EvaluateExpression(e.BoundExpression);
if (e.Variable.Local) if (e.Variable.Local)
{ {
Scope.Set(e.Variable, val); Scope.Set(e.Variable, val, true);
} }
else else
{ {
@ -307,9 +318,9 @@ namespace Upsilon.Evaluator
continue; continue;
if (variableSymbol.Name == "_") if (variableSymbol.Name == "_")
continue; continue;
var value = table.Get(_diagnostics, e.Span, new NumberLong(i + 1), Scope); var value = table.Get(_diagnostics, e.Span, new ScriptNumberLong(i + 1), Scope);
if (variableSymbol.Local) if (variableSymbol.Local)
Scope.Set(variableSymbol, value); Scope.Set(variableSymbol, value, true);
else else
Scope.SetGlobal(variableSymbol, value); Scope.SetGlobal(variableSymbol, value);
} }
@ -321,7 +332,7 @@ namespace Upsilon.Evaluator
_lastValue = val; _lastValue = val;
} }
private LuaType EvaluateVariableExpression(BoundVariableExpression e) private ScriptType EvaluateVariableExpression(BoundVariableExpression e)
{ {
if (Scope.TryGet(e.Variable, out var val)) if (Scope.TryGet(e.Variable, out var val))
{ {
@ -345,7 +356,7 @@ namespace Upsilon.Evaluator
private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement) private void EvaluateBoundIfStatement(BoundIfStatement boundBlockStatement)
{ {
var condition = EvaluateExpression(boundBlockStatement.Condition.Expression); var condition = EvaluateExpression(boundBlockStatement.Condition.Expression);
if ((LuaBoolean) condition) if ((ScriptBoolean) condition)
{ {
EvaluateStatement(boundBlockStatement.Block); EvaluateStatement(boundBlockStatement.Block);
} }
@ -363,31 +374,31 @@ namespace Upsilon.Evaluator
{ {
var func = EvaluateBoundFunctionStatement(e.Func); var func = EvaluateBoundFunctionStatement(e.Func);
if (e.Variable.Local) if (e.Variable.Local)
Scope.Set(e.Variable, func); Scope.Set(e.Variable, func, true);
else else
Scope.SetGlobal(e.Variable, func); Scope.SetGlobal(e.Variable, func);
} }
private LuaType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression) private ScriptType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression)
{ {
var func = new LuaInternalFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope); var func = new ScriptInternalFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope);
return func; return func;
} }
private LuaType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression) private ScriptType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression)
{ {
var func = new LuaInternalFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope); var func = new ScriptInternalFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope);
return func; return func;
} }
private LuaType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression) private ScriptType EvaluateBoundFunctionCallExpression(BoundFunctionCallExpression boundFunctionCallExpression)
{ {
var variable = EvaluateExpression(boundFunctionCallExpression.Identifier); var variable = EvaluateExpression(boundFunctionCallExpression.Identifier);
if (!(variable is LuaFunction function)) if (!(variable is ScriptFunction function))
{ {
throw new Exception($"Variable is not a function."); throw new Exception($"Variable is not a function.");
} }
var ls = new List<LuaType>(); var ls = new List<ScriptType>();
foreach (var t in boundFunctionCallExpression.Parameters) foreach (var t in boundFunctionCallExpression.Parameters)
{ {
var evaluate = EvaluateExpression(t); var evaluate = EvaluateExpression(t);
@ -405,7 +416,7 @@ namespace Upsilon.Evaluator
HasReturned = true; HasReturned = true;
} }
private LuaType EvaluateTableExpression(BoundTableExpression e) private ScriptType EvaluateTableExpression(BoundTableExpression e)
{ {
var tableScope = EvaluationScope.CreateWithGetOnlyParent(Scope); var tableScope = EvaluationScope.CreateWithGetOnlyParent(Scope);
var innerEvaluator = new Evaluator(_diagnostics, tableScope); var innerEvaluator = new Evaluator(_diagnostics, tableScope);
@ -424,7 +435,7 @@ namespace Upsilon.Evaluator
innerEvaluator.EvaluateStatement(boundStatement); innerEvaluator.EvaluateStatement(boundStatement);
if (innerEvaluator._lastValue != null) if (innerEvaluator._lastValue != null)
tableScope.Set(new VariableSymbol(currentPos.ToString(), innerEvaluator._lastValue.Type, false), tableScope.Set(new VariableSymbol(currentPos.ToString(), innerEvaluator._lastValue.Type, false),
innerEvaluator._lastValue); innerEvaluator._lastValue, true);
innerEvaluator._lastValue = null; innerEvaluator._lastValue = null;
break; break;
} }
@ -432,10 +443,10 @@ namespace Upsilon.Evaluator
currentPos++; currentPos++;
} }
return new LuaTable(tableScope); return new ScriptTable(tableScope);
} }
private LuaType EvaluateIndexExpression(BoundIndexExpression e) private ScriptType EvaluateIndexExpression(BoundIndexExpression e)
{ {
var variable = EvaluateExpression(e.Identifier); var variable = EvaluateExpression(e.Identifier);
if (!(variable is IIndexable indexable)) if (!(variable is IIndexable indexable))
@ -451,7 +462,7 @@ namespace Upsilon.Evaluator
var indexer = EvaluateExpression(e.Index); var indexer = EvaluateExpression(e.Index);
return indexable.Get(_diagnostics, e.Span, indexer, scope); return indexable.Get(_diagnostics, e.Span, indexer, scope);
} }
private LuaType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e) private ScriptType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e)
{ {
var variable = EvaluateExpression(e.Expression); var variable = EvaluateExpression(e.Expression);
if (!(variable is IIndexable indexable)) if (!(variable is IIndexable indexable))
@ -470,8 +481,8 @@ namespace Upsilon.Evaluator
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e) private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
{ {
LuaType table; ScriptType table;
LuaType index; ScriptType index;
if (e.TableIndexExpression.Kind == BoundKind.BoundIndexExpression) if (e.TableIndexExpression.Kind == BoundKind.BoundIndexExpression)
{ {
table = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Identifier); table = EvaluateExpression(((BoundIndexExpression)e.TableIndexExpression).Identifier);
@ -494,13 +505,13 @@ namespace Upsilon.Evaluator
private void EvaluateNumericForStatement(BoundNumericForStatement e) private void EvaluateNumericForStatement(BoundNumericForStatement e)
{ {
var innerEvaluator = new Evaluator(_diagnostics, Scope); var innerEvaluator = new Evaluator(_diagnostics, Scope);
var startVal = (NumberLong)innerEvaluator.EvaluateExpression(e.BoundStart); var startVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStart);
innerEvaluator.Scope.Set(e.Variable, startVal); innerEvaluator.Scope.Set(e.Variable, startVal, true);
var stopVal = (NumberLong)innerEvaluator.EvaluateExpression(e.BoundStop); var stopVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStop);
long step = 1; long step = 1;
if (e.BoundStep != null) if (e.BoundStep != null)
{ {
var stepVal = (NumberLong)innerEvaluator.EvaluateExpression(e.BoundStep); var stepVal = (ScriptNumberLong)innerEvaluator.EvaluateExpression(e.BoundStep);
step = stepVal.Value; step = stepVal.Value;
} }
@ -523,5 +534,32 @@ namespace Upsilon.Evaluator
} }
} }
} }
private void EvaluateGenericForStatement(BoundGenericForStatement e)
{
var innerEvaluator = new Evaluator(_diagnostics, Scope);
var enumeratorObject = EvaluateExpression(e.BoundEnumerableExpression);
if (!(enumeratorObject is IIterable iterable))
{
throw new Exception($"Can't iterate over object with type '{enumeratorObject.Type}'");
}
using (var enumerator = iterable.GetEnumerator())
{
bool first = true;
while (enumerator.MoveNext())
{
var (key, value) = enumerator.Current;
if (e.Variables[0].Name != "_")
innerEvaluator.Scope.Set(e.Variables[0], key.ToLuaType(), first);
if (e.Variables[1].Name != "_")
innerEvaluator.Scope.Set(e.Variables[1], value, first);
innerEvaluator.EvaluateBoundBlockStatement((BoundBlockStatement) e.Block);
if (innerEvaluator.HasBroken)
break;
first = false;
}
}
}
} }
} }

View File

@ -64,7 +64,7 @@ namespace Upsilon.Evaluator
public object EvaluateFunction(string functionName, object[] parameters = null) public object EvaluateFunction(string functionName, object[] parameters = null)
{ {
var luaParameters = ImmutableArray.CreateBuilder<LuaType>(); var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
if (parameters != null) if (parameters != null)
{ {
foreach (var parameter in parameters) foreach (var parameter in parameters)
@ -75,7 +75,7 @@ namespace Upsilon.Evaluator
return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable())); return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
} }
private static T Convert<T>(LuaType t) private static T Convert<T>(ScriptType t)
{ {
if (typeof(T) == typeof(double)) if (typeof(T) == typeof(double))
return (T)(object)System.Convert.ToDouble(t.ToCSharpObject()); return (T)(object)System.Convert.ToDouble(t.ToCSharpObject());
@ -84,7 +84,7 @@ namespace Upsilon.Evaluator
return (T) t.ToCSharpObject(); return (T) t.ToCSharpObject();
} }
private static object Convert(LuaType t) private static object Convert(ScriptType t)
{ {
return t?.ToCSharpObject(); return t?.ToCSharpObject();
} }
@ -98,7 +98,7 @@ namespace Upsilon.Evaluator
public T EvaluateFunction<T>(string functionName, object[] parameters = null) public T EvaluateFunction<T>(string functionName, object[] parameters = null)
{ {
var luaParameters = ImmutableArray.CreateBuilder<LuaType>(); var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
if (parameters != null) if (parameters != null)
{ {
foreach (var parameter in parameters) foreach (var parameter in parameters)

View File

@ -166,13 +166,29 @@ namespace Upsilon.Parser
var doToken = MatchToken(SyntaxKind.DoKeyword); var doToken = MatchToken(SyntaxKind.DoKeyword);
var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword}); var block = ParseBlockStatement(new []{SyntaxKind.EndKeyword});
var endToken = MatchToken(SyntaxKind.EndKeyword); var endToken = MatchToken(SyntaxKind.EndKeyword);
return new NumericForStatementSyntax(forToken, identifier, equals, v1, comma1, v2, comma2, v3, doToken, return new NumericForStatementSyntax(forToken, identifier, equals, v1, comma1,
block, endToken); v2, comma2, v3, doToken, block, endToken);
} }
private StatementSyntax ParseGenericForStatement(SyntaxToken forToken) private StatementSyntax ParseGenericForStatement(SyntaxToken forToken)
{ {
throw new NotImplementedException(); var arr = ImmutableArray.CreateBuilder<IdentifierToken>();
while (true)
{
var identifier = MatchToken(SyntaxKind.Identifier);
arr.Add((IdentifierToken) identifier);
if (Current.Kind == SyntaxKind.InKeyword)
break;
MatchToken(SyntaxKind.Comma);
}
var inKeyword = MatchToken(SyntaxKind.InKeyword);
var enumerableExpression = ParseExpression();
var doKeyword = MatchToken(SyntaxKind.DoKeyword);
var block = ParseBlockStatement(new[] {SyntaxKind.EndKeyword});
var endKeyword = MatchToken(SyntaxKind.EndKeyword);
return new GenericForStatementSyntax(forToken, arr.ToImmutable(), inKeyword, enumerableExpression,
doKeyword, (BlockStatementSyntax) block, endKeyword);
} }
private ExpressionSyntax ParseFunctionExpression() private ExpressionSyntax ParseFunctionExpression()

View File

@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Upsilon.Parser
{
public class GenericForStatementSyntax : StatementSyntax
{
public SyntaxToken ForKeyword { get; }
public ImmutableArray<IdentifierToken> Variables { get; }
public SyntaxToken InKeyword { get; }
public ExpressionSyntax EnumerableExpression { get; }
public SyntaxToken DoKeyword { get; }
public BlockStatementSyntax Block { get; }
public SyntaxToken EndKeyword { get; }
public GenericForStatementSyntax(SyntaxToken forKeyword, ImmutableArray<IdentifierToken> variables, SyntaxToken inKeyword,
ExpressionSyntax enumerableExpression, SyntaxToken doKeyword, BlockStatementSyntax block, SyntaxToken endKeyword)
{
ForKeyword = forKeyword;
Variables = variables;
InKeyword = inKeyword;
EnumerableExpression = enumerableExpression;
DoKeyword = doKeyword;
Block = block;
EndKeyword = endKeyword;
}
public override SyntaxKind Kind => SyntaxKind.GenericForStatement;
public override IEnumerable<SyntaxNode> ChildNodes()
{
yield return ForKeyword;
foreach (var identifierToken in Variables)
yield return identifierToken;
yield return InKeyword;
yield return EnumerableExpression;
yield return DoKeyword;
yield return Block;
yield return EndKeyword;
}
}
}

View File

@ -78,6 +78,7 @@ namespace Upsilon.Parser
FunctionAssignmentStatement, FunctionAssignmentStatement,
TableAssignmentStatement, TableAssignmentStatement,
NumericForStatement, NumericForStatement,
BreakStatement BreakStatement,
GenericForStatement
} }
} }

View File

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.BaseTypes.LuaTypeInterfaces; using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Type = Upsilon.BaseTypes.Type;
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global // ReSharper disable MemberCanBePrivate.Global
@ -25,15 +27,29 @@ namespace Upsilon.StandardLibraries
throw new Exception(message); throw new Exception(message);
} }
/*
[LuaFunction("ipairs")] [LuaFunction("ipairs")]
public LuaType Pairs(IIterable table) public ScriptType Pairs(IIterable table)
{ {
if (!table.Next(out var key, out var next)) if (!table.Next(out var key, out var next))
{ {
return new LuaNull(); return new ScriptNull();
} }
return new SimpleLuaTable(new List<LuaType>() {key, next}); return new SimpleScriptTable(new List<ScriptType>() {key, next});
}*/
[LuaFunction("tonumber")]
public ScriptNumber ToNumber(string str)
{
if (str.Contains("."))
{
return new ScriptNumberDouble(double.Parse(str));
}
else
{
return new ScriptNumberLong(long.Parse(str));
}
} }
} }
} }

View File

@ -7,16 +7,16 @@ namespace Upsilon.StandardLibraries
{ {
internal abstract class LuaLibrary internal abstract class LuaLibrary
{ {
public Dictionary<string, LuaFunction> LoadMethods() public Dictionary<string, ScriptFunction> LoadMethods()
{ {
var dictionary = new Dictionary<string, LuaFunction>(); var dictionary = new Dictionary<string, ScriptFunction>();
var methods = GetType().GetMethods(); var methods = GetType().GetMethods();
foreach (var methodInfo in methods) foreach (var methodInfo in methods)
{ {
var attr = methodInfo.GetCustomAttribute<LuaFunctionAttribute>(); var attr = methodInfo.GetCustomAttribute<LuaFunctionAttribute>();
if (attr != null) if (attr != null)
{ {
dictionary.Add(attr.Name, new LuaMethodInfoFunction(new UserDataMethod(methodInfo), this)); dictionary.Add(attr.Name, new ScriptMethodInfoFunction(new UserDataMethod(methodInfo), this));
} }
} }

View File

@ -42,7 +42,7 @@ namespace Upsilon.StandardLibraries
public static (EvaluationScope, BoundScope) CreateStandardLibrary() public static (EvaluationScope, BoundScope) CreateStandardLibrary()
{ {
var basicFunctions = new BasicFunctions().LoadMethods(); var basicFunctions = new BasicFunctions().LoadMethods();
var scope = new EvaluationScope(basicFunctions.ToDictionary(x => x.Key, x => (LuaType)x.Value)); var scope = new EvaluationScope(basicFunctions.ToDictionary(x => x.Key, x => (ScriptType)x.Value));
var boundScope = var boundScope =
new BoundScope( new BoundScope(
scope.Variables.ToDictionary(x => x.Key scope.Variables.ToDictionary(x => x.Key
@ -56,7 +56,7 @@ namespace Upsilon.StandardLibraries
var luaVariable = value.ToLuaType(); var luaVariable = value.ToLuaType();
var varSymbol = new VariableSymbol(name, luaVariable.Type, false); var varSymbol = new VariableSymbol(name, luaVariable.Type, false);
BoundScope.SetVariable(varSymbol); BoundScope.SetVariable(varSymbol);
Scope.Set(varSymbol, luaVariable); Scope.Set(varSymbol, luaVariable, true);
} }
} }
} }

View File

@ -79,5 +79,42 @@ return a
Assert.Equal(15, result); Assert.Equal(15, result);
} }
[Fact]
public void GenericForLoopValueTest()
{
const string input = @"
arr = {100, 56, 28}
value = 0
for key, val in arr do
value = value + val
end
return value
";
var script = new Script(input, BoundScope, StaticScope);
Assert.Empty(script.Diagnostics.Messages);
var result = script.Evaluate<long>();
Assert.Empty(script.Diagnostics.Messages);
Assert.Equal(184, result);
}
[Fact]
public void GenericForLoopKeyTest()
{
const string input = @"
arr = {100, 56, 28}
value = 0
for key, val in arr do
local keyInt = tonumber(key)
value = value + keyInt
end
return value
";
var script = new Script(input, BoundScope, StaticScope);
Assert.Empty(script.Diagnostics.Messages);
var result = script.Evaluate<long>();
Assert.Empty(script.Diagnostics.Messages);
Assert.Equal(6, result);
}
} }
} }