Skip to content

Commit

Permalink
Merge pull request #60 from WattleScript/feat-field-info
Browse files Browse the repository at this point in the history
Improve field info of classes&mixins
  • Loading branch information
CallumDev authored Oct 10, 2022
2 parents 5d11969 + 28515f6 commit c15a84f
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 88 deletions.
22 changes: 0 additions & 22 deletions src/WattleScript.Interpreter/DataTypes/PrivateKeyInfo.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/WattleScript.Interpreter/DataTypes/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ public TableKind Kind
public MemberModifierFlags ModifierFlags { get; set; }

/// <summary>
/// Holds information relating to private keys (if present)
/// Holds modifiers of declared fields & functions in case <see cref="TableKind"/> is Class/Mixin. Can be null.
/// </summary>
public PrivateKeyInfo PrivateKeys { get; set; }
public WattleMembersInfo Members { get; set; }

/// <summary>
/// Removes all items from the Table.
Expand Down
9 changes: 6 additions & 3 deletions src/WattleScript.Interpreter/DataTypes/WattleMemberInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ namespace WattleScript.Interpreter
{
internal class WattleMemberInfo
{
public string Name { get; set; }
public string Name => Token.Text;
public MemberModifierFlags Flags { get; set; }
public Expression Expr { get; set; }
public Token Token { get; set; }
public bool IsFunction { get; set; }

public WattleMemberInfo(string name, Expression expr, MemberModifierFlags flags)
public WattleMemberInfo(Token token, Expression expr, MemberModifierFlags flags, bool isFunction)
{
Name = name;
Token = token;
Expr = expr;
Flags = flags;
IsFunction = isFunction;
}
}
}
30 changes: 30 additions & 0 deletions src/WattleScript.Interpreter/DataTypes/WattleMembersInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;

namespace WattleScript.Interpreter
{
public sealed class WattleMembersInfo
{
public IReadOnlyDictionary<string, MemberModifierFlags> Modifiers => i_Modifiers;

internal readonly Dictionary<string, MemberModifierFlags> i_Modifiers = new Dictionary<string, MemberModifierFlags>();

public bool MemberHasModifier(string memberName, MemberModifierFlags modifier)
{
return MemberHasModifier(DynValue.NewString(memberName), modifier);
}

public bool MemberHasModifier(DynValue memberName, MemberModifierFlags modifier)
{
if (memberName.Type != DataType.String) return false;
return i_Modifiers.TryGetValue(memberName.String, out MemberModifierFlags flags) && flags.HasFlag(modifier);
}

internal void Merge(WattleMembersInfo parent)
{
parent.i_Modifiers.ToList().ForEach(x => i_Modifiers[x.Key] = x.Value);
}

internal WattleMembersInfo() { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
case OpCode.PushNil:
case OpCode.PushTrue:
case OpCode.PushFalse:
case OpCode.CopyPriv:
case OpCode.CopyFlags:
return InstructionFieldUsage.None;
case OpCode.Pop:
case OpCode.Copy:
Expand All @@ -53,7 +53,6 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
case OpCode.Less:
case OpCode.Eq:
case OpCode.CNot:
case OpCode.SetPriv:
return InstructionFieldUsage.NumVal;
case OpCode.Jump:
case OpCode.Jf:
Expand All @@ -70,7 +69,8 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
case OpCode.JLclInit:
case OpCode.Args:
case OpCode.TblInitN:
case OpCode.MergePriv:
case OpCode.MergeFlags:
case OpCode.SetFlags:
return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
case OpCode.Local:
case OpCode.Upvalue:
Expand Down
12 changes: 6 additions & 6 deletions src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,19 @@ public int Emit_TabProps(TableKind kind, MemberModifierFlags flags, bool isReadO
return AppendInstruction(new Instruction(OpCode.TabProps, (int) flags, (int)kind, isReadOnly ? (uint)1 : 0));
}

public int Emit_SetPriv(int num)
public int Emit_SetFlags(int num, MemberModifierFlags flags)
{
return AppendInstruction(new Instruction(OpCode.SetPriv, num));
return AppendInstruction(new Instruction(OpCode.SetFlags, num, (int)flags));
}

public int Emit_MergePriv(int src, int dst)
public int Emit_MergeFlags(int src, int dst)
{
return AppendInstruction(new Instruction(OpCode.MergePriv, src, dst));
return AppendInstruction(new Instruction(OpCode.MergeFlags, src, dst));
}

public int Emit_CopyPriv()
public int Emit_CopyFlags()
{
return AppendInstruction(new Instruction(OpCode.CopyPriv));
return AppendInstruction(new Instruction(OpCode.CopyFlags));
}

public int Emit_Pop(int num = 1)
Expand Down
6 changes: 3 additions & 3 deletions src/WattleScript.Interpreter/Execution/VM/OpCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ internal enum OpCode
//Throws error using class name in NumValB if type check fails
MixInit, //Checks type of mixin on v-stack top, stores init to v-stack + 1, adds functions to v-stack + 2, pops top
//Error check uses NumVal for mixin name
SetPriv, //Sets NumVal keys to private (pops NumVal items)
MergePriv, //Merges the PrivateKeyInfo of v-stack(NumVal) into v-stack(NumVal2)
CopyPriv, //Copies the PrivateKeyInfo of v-stack top into v-stack +1, pops 1 value
SetFlags, //Sets WattleFieldsInfo for NumVal keys, using modifier in NumVal2 (pops NumVal Items)
MergeFlags, //Merges the WattleFieldsInfo of v-stack(NumVal) into v-stack(NumVal2)
CopyFlags, //Copies the WattleFieldsInfo of v-stack top into v-stack +1, pops 1 value
// Meta
Invalid, // Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,14 +390,14 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false)
case OpCode.NewRange:
ExecNewRange(i);
break;
case OpCode.SetPriv:
ExecSetPriv(i);
case OpCode.SetFlags:
ExecSetFlags(i);
break;
case OpCode.CopyPriv:
ExecCopyPriv(i);
case OpCode.CopyFlags:
ExecCopyFlags(i);
break;
case OpCode.MergePriv:
ExecMergePriv(i);
case OpCode.MergeFlags:
ExecMergeFlags(i);
break;
case OpCode.ToNum:
{
Expand Down Expand Up @@ -628,37 +628,37 @@ private void ExecExpTuple(Instruction i)

}

private void ExecSetPriv(Instruction i)
private void ExecSetFlags(Instruction i)
{
ref DynValue t = ref m_ValueStack.Peek(i.NumVal);
if (t.Type != DataType.Table)
throw new InternalErrorException("SETPRIV called on non-table object");
t.Table.PrivateKeys = new PrivateKeyInfo();
throw new InternalErrorException("SETFLAGS called on non-table object");
t.Table.Members ??= new WattleMembersInfo();
while (i.NumVal-- > 0) {
t.Table.PrivateKeys.Fields.Add(m_ValueStack.Pop().CastToString());
t.Table.Members.i_Modifiers.Add(m_ValueStack.Pop().CastToString(), (MemberModifierFlags)i.NumVal2);
}
}

private void ExecCopyPriv(Instruction i)
private void ExecCopyFlags(Instruction i)
{
ref DynValue dest = ref m_ValueStack.Peek(1);
ref DynValue src = ref m_ValueStack.Peek(0);
if (dest.Type != DataType.Table || src.Type != DataType.Table)
throw new InternalErrorException("COPYPRIV called on non-table object");
dest.Table.PrivateKeys = src.Table.PrivateKeys;
throw new InternalErrorException("COPYFLAGS called on non-table object");
dest.Table.Members ??= src.Table.Members;
m_ValueStack.Pop();
}

private void ExecMergePriv(Instruction i)
private void ExecMergeFlags(Instruction i)
{
ref DynValue dest = ref m_ValueStack.Peek(i.NumVal2);
ref DynValue src = ref m_ValueStack.Peek(i.NumVal);
if (dest.Type != DataType.Table || src.Type != DataType.Table)
throw new InternalErrorException("MERGEPRIV called on non-table object");
if (src.Table.PrivateKeys != null)
throw new InternalErrorException("MERGEFLAGS called on non-table object");
if (src.Table.Members != null)
{
dest.Table.PrivateKeys ??= new PrivateKeyInfo();
dest.Table.PrivateKeys.Merge(src.Table.PrivateKeys);
dest.Table.Members ??= new WattleMembersInfo();
dest.Table.Members.Merge(src.Table.Members);
}
}

Expand Down Expand Up @@ -1765,8 +1765,8 @@ private int ExecIndexSet(Instruction i, int instructionPtr)
if (!isMultiIndex)
{
//Private fields - error on write
if (!accessPrivate && obj.Table.PrivateKeys != null &&
obj.Table.PrivateKeys.IsKeyPrivate(idx))
if (!accessPrivate && obj.Table.Members != null &&
obj.Table.Members.MemberHasModifier(idx, MemberModifierFlags.Private))
{
throw new ScriptRuntimeException($"cannot write to private key '{idx.ToPrintString()}'");
}
Expand Down Expand Up @@ -1877,8 +1877,8 @@ private int ExecIndex(Instruction i, int instructionPtr)
if (!isMultiIndex)
{
//Don't return private fields
if (!accessPrivate && obj.Table.PrivateKeys != null &&
obj.Table.PrivateKeys.IsKeyPrivate(idx))
if (!accessPrivate && obj.Table.Members != null &&
obj.Table.Members.MemberHasModifier(idx, MemberModifierFlags.Private))
{
m_ValueStack.Push(DynValue.Nil);
return instructionPtr;
Expand Down
28 changes: 26 additions & 2 deletions src/WattleScript.Interpreter/Tree/MemberCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal class MemberCollection : IEnumerable<WattleMemberInfo>
{
private List<WattleMemberInfo> items = new List<WattleMemberInfo>();
private HashSet<string> names = new HashSet<string>();

public IEnumerator<WattleMemberInfo> GetEnumerator()
{
return items.GetEnumerator();
Expand All @@ -30,7 +30,31 @@ public void Add(Token nameToken, Expression expression, MemberModifierFlags modi
);
}
names.Add(nameToken.Text);
items.Add(new WattleMemberInfo(nameToken.Text, expression, modifiers));
items.Add(new WattleMemberInfo(nameToken, expression, modifiers, isFunction));
}

public void Add(WattleMemberInfo info)
{
if (names.Contains(info.Name))
{
throw new SyntaxErrorException(
info.Token,
"duplicate declaration of a {0} '{1}'",
info.IsFunction ? "function" : "field",
info.Name
);
}

names.Add(info.Name);
items.Add(info);
}

public void Add(MemberCollection memberCollection)
{
foreach (WattleMemberInfo info in memberCollection)
{
Add(info);
}
}

public int Count => items.Count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ void CompileInit(FunctionBuilder parent)
//mixin init table
//mixin ref
mixinRefs[n].Compile(bc);
bc.Emit_MergePriv(0, 3);
bc.Emit_MergeFlags(0, 3);
bc.Emit_MixInit(n);
}
//stack: class, __index, init table
Expand Down Expand Up @@ -336,7 +336,7 @@ void CompileInit(FunctionBuilder parent)
//Set Base member, copy private field info + leave on stack
baseSym.Compile(bc);
sym[localName].Compile(bc);
bc.Emit_MergePriv(1, 0);
bc.Emit_MergeFlags(1, 0);
bc.Emit_IndexSet(0, 0, "Base");
//Base resolved, call __init
bc.SetNumVal(jp2, bc.GetJumpPointForNextInstruction());
Expand All @@ -351,7 +351,7 @@ void CompileInit(FunctionBuilder parent)
sym["table"].Compile(bc);
sym["this"].CompileAssignment(bc, Operator.NotAnOperator, 0, 0);
sym[localName].Compile(bc);
bc.Emit_CopyPriv();
bc.Emit_CopyFlags();
foreach (var field in fields.Where(x => !x.Flags.HasFlag(MemberModifierFlags.Static)))
{
field.Expr.CompilePossibleLiteral(bc);
Expand Down Expand Up @@ -459,18 +459,24 @@ public override void Compile(FunctionBuilder bc)
//set metadata and store to local
foreach(var annot in annotations)
bc.Emit_Annot(annot);
int privateCount = 0;
foreach (var fn in functions.Where(x => x.Flags.HasFlag(MemberModifierFlags.Private))) {
privateCount++;
bc.Emit_Literal(DynValue.NewString(fn.Name));
}
foreach (var field in fields.Where(x => x.Flags.HasFlag(MemberModifierFlags.Private))) {
privateCount++;
bc.Emit_Literal(DynValue.NewString(field.Name));
}
if (privateCount > 0) {
bc.Emit_SetPriv(privateCount);
// group members by flags
MemberCollection memberAccumulator = new MemberCollection();
memberAccumulator.Add(functions);
memberAccumulator.Add(fields);

foreach (IGrouping<MemberModifierFlags, WattleMemberInfo> group in memberAccumulator.GroupBy(x => x.Flags))
{
int groupCount = 0;

foreach (WattleMemberInfo memberInfo in group)
{
groupCount++;
bc.Emit_Literal(DynValue.NewString(memberInfo.Name));
}

bc.Emit_SetFlags(groupCount, group.Key);
}

bc.Emit_TabProps(TableKind.Class, flags, false);
classStoreLocal.CompileAssignment(bc, Operator.NotAnOperator, 0, 0);
//set global to class name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,23 @@ public override void Compile(FunctionBuilder bc)
//set metadata and store global
foreach(var annot in annotations)
bc.Emit_Annot(annot);
int privateCount = 0;
foreach (var fn in functions.Where(x => x.Flags.HasFlag(MemberModifierFlags.Private))) {
privateCount++;
bc.Emit_Literal(DynValue.NewString(fn.Name));
}
foreach (var field in fields.Where(x => x.Flags.HasFlag(MemberModifierFlags.Private))) {
privateCount++;
bc.Emit_Literal(DynValue.NewString(field.Name));
}
if (privateCount > 0) {
bc.Emit_SetPriv(privateCount);
MemberCollection memberAccumulator = new MemberCollection();
memberAccumulator.Add(functions);
memberAccumulator.Add(fields);

foreach (IGrouping<MemberModifierFlags, WattleMemberInfo> group in memberAccumulator.GroupBy(x => x.Flags))
{
int groupCount = 0;

foreach (WattleMemberInfo memberInfo in group)
{
groupCount++;
bc.Emit_Literal(DynValue.NewString(memberInfo.Name));
}

bc.Emit_SetFlags(groupCount, group.Key);
}

bc.Emit_TabProps(TableKind.Mixin, MemberModifierFlags.None, true);
storeValue.CompileAssignment(bc, Operator.NotAnOperator, 0, 0);
bc.Emit_Leave(scopeBlock);
Expand Down

0 comments on commit c15a84f

Please sign in to comment.