Skip to content

Commit f70c24d

Browse files
authored
Merge pull request #54 from WattleScript/feat-static-lofcz
Static classes
2 parents 810a616 + c6ad39e commit f70c24d

36 files changed

+317
-52
lines changed

src/WattleScript.Interpreter/DataTypes/MemberModifierFlags.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace WattleScript.Interpreter
44
{
55
[Flags]
6-
internal enum MemberModifierFlags
6+
public enum MemberModifierFlags
77
{
88
None = 0,
99
Static = 1

src/WattleScript.Interpreter/DataTypes/Table.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ public Table(Script owner, params DynValue[] arrayValues)
6363
/// This is only for metadata purposes, and does not affect execution.
6464
/// </summary>
6565
public TableKind Kind { get; set; }
66+
67+
/// <summary>
68+
/// Gets/sets the modifiers of table.
69+
/// This is only for metadata purposes, and does not affect execution.
70+
/// </summary>
71+
public MemberModifierFlags ModifierFlags { get; set; }
6672

6773
/// <summary>
6874
/// Removes all items from the Table.

src/WattleScript.Interpreter/Errors/ScriptRuntimeException.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,32 @@ public static ScriptRuntimeException NotAClass(string name, DynValue value)
8989
throw new ScriptRuntimeException($"'{name}' is invalid class (expected class, got {ExtTypeStr(value)})");
9090
}
9191

92+
/// <summary>
93+
/// Creates a ScriptRuntimeException with a predefined error message specifying that
94+
/// a specified value is not a class
95+
/// </summary>
96+
/// <param name="modifier">The incompatible modifier</param>
97+
/// <param name="name">The name the value was indexed from</param>
98+
/// <param name="value">The referencing type</param>
99+
/// <returns>The exception to be raised</returns>
100+
public static ScriptRuntimeException NewCallIncompatibleModifier(string modifier, string name, DynValue value)
101+
{
102+
throw new ScriptRuntimeException($"{modifier} {ExtTypeStr(value)} '{name}' cannot be instantiated.");
103+
}
104+
105+
/// <summary>
106+
/// Creates a ScriptRuntimeException with a predefined error message specifying that
107+
/// a specified value is not a class
108+
/// </summary>
109+
/// <param name="modifier">The incompatible modifier</param>
110+
/// <param name="ancestorName">The name of child class</param>
111+
/// <param name="descendantName">The name of parent class</param>
112+
/// <returns>The exception to be raised</returns>
113+
public static ScriptRuntimeException BaseInvalidModifier(string modifier, string ancestorName, string descendantName)
114+
{
115+
throw new ScriptRuntimeException($"class '{descendantName}' cannot inherit from {modifier} class '{ancestorName}'.");
116+
}
117+
92118
/// <summary>
93119
/// Creates a ScriptRuntimeException with a predefined error message specifying that
94120
/// a specified value is not a mixin

src/WattleScript.Interpreter/Execution/InstructionFieldUsage.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
3838
case OpCode.PushNil:
3939
case OpCode.PushTrue:
4040
case OpCode.PushFalse:
41-
case OpCode.SetMetaTab:
4241
return InstructionFieldUsage.None;
4342
case OpCode.Pop:
4443
case OpCode.Copy:
@@ -68,7 +67,6 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
6867
case OpCode.CopyValue:
6968
case OpCode.JLclInit:
7069
case OpCode.Args:
71-
case OpCode.TabProps:
7270
case OpCode.TblInitN:
7371
return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
7472
case OpCode.Local:
@@ -81,7 +79,8 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
8179
case OpCode.StoreUpv:
8280
case OpCode.NewRange:
8381
case OpCode.TblInitI:
84-
return InstructionFieldUsage.NumVal3 | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2;
82+
case OpCode.TabProps:
83+
return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2 | InstructionFieldUsage.NumVal3;
8584
case OpCode.Index:
8685
case OpCode.IndexL:
8786
case OpCode.IndexN:
@@ -93,9 +92,10 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
9392
case OpCode.Invalid:
9493
case OpCode.MixInit:
9594
case OpCode.PushString:
96-
case OpCode.PushInt:
97-
return InstructionFieldUsage.NumVal;
9895
case OpCode.PushNumber:
96+
case OpCode.PushInt:
97+
case OpCode.BaseChk:
98+
case OpCode.SetMetaTab:
9999
return InstructionFieldUsage.NumVal;
100100
case OpCode.Call:
101101
case OpCode.ThisCall:
@@ -111,6 +111,7 @@ internal static InstructionFieldUsage GetFieldUsage(this OpCode op)
111111
case OpCode.AnnotB:
112112
case OpCode.AnnotS:
113113
case OpCode.AnnotN:
114+
case OpCode.LoopChk:
114115
return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumValB;
115116
case OpCode.AnnotT:
116117
return InstructionFieldUsage.NumValB;

src/WattleScript.Interpreter/Execution/VM/FunctionBuilder.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ public int Emit_Invalid(string type)
197197
return AppendInstruction(new Instruction(OpCode.Invalid));
198198
}
199199

200-
public int Emit_TabProps(TableKind kind, bool isReadOnly)
200+
public int Emit_TabProps(TableKind kind, MemberModifierFlags flags, bool isReadOnly)
201201
{
202-
return AppendInstruction(new Instruction(OpCode.TabProps, (int) kind, isReadOnly ? 1 : 0));
202+
return AppendInstruction(new Instruction(OpCode.TabProps, (int) kind, (int)flags, isReadOnly ? (uint)1 : 0));
203203
}
204204

205205

@@ -571,6 +571,11 @@ public int Emit_SetMetaTab()
571571
{
572572
return AppendInstruction(new Instruction(OpCode.SetMetaTab));
573573
}
574+
575+
public int Emit_SetMetaTab(string name)
576+
{
577+
return AppendInstruction(new Instruction(OpCode.SetMetaTab, StringArg(name)));
578+
}
574579

575580
public int Emit_TblInitI(bool lastpos, int count, int create)
576581
{

src/WattleScript.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false)
276276
ref var top = ref m_ValueStack.Peek();
277277
if (top.Type != DataType.Table) throw new InternalErrorException("v-stack top NOT table");
278278
top.Table.Kind = (TableKind)i.NumVal;
279-
top.Table.ReadOnly = i.NumVal2 != 0;
279+
top.Table.ReadOnly = i.NumVal3 != 0;
280+
top.Table.ModifierFlags = (MemberModifierFlags)i.NumVal2;
280281
break;
281282
}
282283
case OpCode.SetMetaTab:
@@ -285,6 +286,10 @@ private DynValue Processing_Loop(int instructionPtr, bool canAwait = false)
285286
ref var tab = ref m_ValueStack.Peek();
286287
if (top.Type != DataType.Table) throw new InternalErrorException("v-stack top NOT table");
287288
if (tab.Type != DataType.Table) throw new InternalErrorException("v-stack tab NOT table");
289+
if (top.Table.ModifierFlags.HasFlag(MemberModifierFlags.Static))
290+
{
291+
throw ScriptRuntimeException.BaseInvalidModifier(MemberModifierFlags.Static.ToString().ToLowerInvariant(), top.Table.Get("Name").String ?? "(null)", currentFrame.Function.strings[i.NumVal]);
292+
}
288293
tab.Table.MetaTable = top.Table;
289294
break;
290295
}
@@ -1603,6 +1608,8 @@ private int ExecNewCall(Instruction i, int instructionPtr, bool canAwait)
16031608
if (cls.Type != DataType.Table ||
16041609
cls.Table.Kind != TableKind.Class)
16051610
throw ScriptRuntimeException.NotAClass(GetString((int) i.NumValB), cls);
1611+
if (cls.Table.ModifierFlags.HasFlag(MemberModifierFlags.Static))
1612+
throw ScriptRuntimeException.NewCallIncompatibleModifier(MemberModifierFlags.Static.ToString().ToLowerInvariant(), GetString((int) i.NumValB), cls);
16061613
cls = cls.Table.Get("new");
16071614
return Internal_ExecCall(canAwait, i.NumVal, instructionPtr);
16081615
}
@@ -1788,8 +1795,7 @@ private int ExecIndex(Instruction i, int instructionPtr)
17881795

17891796
// stack: base - index
17901797
bool isNameIndex = i.OpCode == OpCode.IndexN;
1791-
1792-
bool isMultiIndex = (i.OpCode == OpCode.IndexL);
1798+
bool isMultiIndex = i.OpCode == OpCode.IndexL;
17931799

17941800
string i_str = GetString(i.NumVal);
17951801
DynValue originalIdx = i_str != null ? DynValue.NewString(i_str) : m_ValueStack.Pop();

src/WattleScript.Interpreter/Extensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System.Collections.Generic;
2+
using System.ComponentModel;
23
using System.Linq;
4+
using System.Reflection;
35
using WattleScript.Interpreter.Debugging;
46

57
namespace WattleScript.Interpreter

src/WattleScript.Interpreter/Tree/Expressions/NewExpression.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ namespace WattleScript.Interpreter.Tree.Expressions
88
{
99
class NewExpression : Expression
1010
{
11+
internal SourceRef SourceRef;
12+
1113
private SymbolRefExpression classRef;
12-
private SourceRef sourceRef;
1314
private List<Expression> arguments;
1415
private string className;
1516

@@ -28,12 +29,12 @@ public NewExpression(ScriptLoadingContext lcontext) : base(lcontext)
2829
arguments = ExprList(lcontext);
2930
}
3031
var end = CheckTokenType(lcontext, TokenType.Brk_Close_Round);
31-
sourceRef = classTok.GetSourceRef(end);
32+
SourceRef = classTok.GetSourceRef(end);
3233
}
3334

3435
public override void Compile(FunctionBuilder bc)
3536
{
36-
bc.PushSourceRef(sourceRef);
37+
bc.PushSourceRef(SourceRef);
3738
classRef.Compile(bc);
3839
foreach(var a in arguments)
3940
a.CompilePossibleLiteral(bc);

src/WattleScript.Interpreter/Tree/GeneratedClosure.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public void ResolveScope(ScriptLoadingContext lcontext, Action<ScriptLoadingCont
5757
{
5858
referenced[s] = new SymbolRefExpression(lcontext, lcontext.Scope.DefineLocal(s));
5959
}
60-
foreach(var e in toResolve) e.ResolveScope(lcontext);
6160
extra?.Invoke(lcontext);
61+
foreach(var e in toResolve) e.ResolveScope(lcontext);
6262
frame = lcontext.Scope.PopFunction();
6363
}
6464

src/WattleScript.Interpreter/Tree/Lexer/Token.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using WattleScript.Interpreter.Tree.Statements;
23

34
namespace WattleScript.Interpreter.Tree
45
{
@@ -128,6 +129,20 @@ public bool IsUnaryOperator()
128129
Type == TokenType.Op_Inc || Type == TokenType.Op_Dec || Type == TokenType.Op_Not;
129130
}
130131

132+
public bool IsMemberModifier()
133+
{
134+
return Type == TokenType.Static;
135+
}
136+
137+
public MemberModifierFlags ToMemberModiferFlag()
138+
{
139+
return Type switch
140+
{
141+
TokenType.Static => MemberModifierFlags.Static,
142+
_ => MemberModifierFlags.None
143+
};
144+
}
145+
131146
public bool IsBinaryOperator()
132147
{
133148
switch (Type)

0 commit comments

Comments
 (0)