add conditionals for logging to actually test performance
This commit is contained in:
parent
367b334b79
commit
4f6d0fdf5b
|
|
@ -62,12 +62,16 @@ public static class Benchmark
|
||||||
|
|
||||||
if (!_clocks.TryGetValue(key, out Stopwatch sw))
|
if (!_clocks.TryGetValue(key, out Stopwatch sw))
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Debug($"No clock found for '{key}', start one first using Benchmark.Start()");
|
_logger.Debug($"No clock found for '{key}', start one first using Benchmark.Start()");
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
#if LOG
|
||||||
_logger.Debug($" ::: {key}:{line} > {message ?? "Elapsed"}: {sw.Elapsed}");
|
_logger.Debug($" ::: {key}:{line} > {message ?? "Elapsed"}: {sw.Elapsed}");
|
||||||
|
#endif
|
||||||
if (keep)
|
if (keep)
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,12 +76,16 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
public Function Digest()
|
public Function Digest()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
TokenPosition previousPosition = _reader.CurrentPosition;
|
TokenPosition previousPosition = _reader.CurrentPosition;
|
||||||
Next();
|
Next();
|
||||||
while (!Done && !Match(T.Eof)) {
|
while (!Done && !Match(T.Eof)) {
|
||||||
Token token = Current;
|
Token token = Current;
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"Digesting {token}");
|
_logger.Verbose($"Digesting {token}");
|
||||||
|
#endif
|
||||||
if (previousPosition == _reader.CurrentPosition) {
|
if (previousPosition == _reader.CurrentPosition) {
|
||||||
ErrorAtCurrent("Loop detected / could not digest further");
|
ErrorAtCurrent("Loop detected / could not digest further");
|
||||||
break;
|
break;
|
||||||
|
|
@ -91,8 +95,12 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
SegmentBuilder _debug = Builder.Function.Segment;
|
SegmentBuilder _debug = Builder.Function.Segment;
|
||||||
Function function = FinishBuilder();
|
Function function = FinishBuilder();
|
||||||
|
#if LOG
|
||||||
_logger.Debug($"Digest done, instruction set:");
|
_logger.Debug($"Digest done, instruction set:");
|
||||||
|
#endif
|
||||||
|
#if LOG
|
||||||
_logger.Verbose(_debug.Debug());
|
_logger.Verbose(_debug.Debug());
|
||||||
|
#endif
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +126,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Process()
|
internal void Process()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
if (Match(T.Class)) DeclareClass();
|
if (Match(T.Class)) DeclareClass();
|
||||||
else if (Match(T.Function)) DeclareFunction();
|
else if (Match(T.Function)) DeclareFunction();
|
||||||
else if (Match(T.Var)) DeclareVariable();
|
else if (Match(T.Var)) DeclareVariable();
|
||||||
|
|
@ -127,7 +137,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Statement()
|
internal void Statement()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
if (Match(T.If)) If();
|
if (Match(T.If)) If();
|
||||||
else if (Match(T.Else)) Else();
|
else if (Match(T.Else)) Else();
|
||||||
else if (Match(T.While)) While();
|
else if (Match(T.While)) While();
|
||||||
|
|
@ -147,7 +159,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Expression()
|
internal void Expression()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
if (Builder.Type == FunctionType.Code && Check(T.Eof))
|
if (Builder.Type == FunctionType.Code && Check(T.Eof))
|
||||||
Emit(Op.Print); // if we got presented with only an expression on top-level code and no ; at the end,
|
Emit(Op.Print); // if we got presented with only an expression on top-level code and no ; at the end,
|
||||||
|
|
@ -166,7 +180,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Context()
|
internal void Context()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
BeginScope();
|
BeginScope();
|
||||||
Block();
|
Block();
|
||||||
EndScope();
|
EndScope();
|
||||||
|
|
@ -174,7 +190,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Block()
|
internal void Block()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
while (!Check(T.ContextClose) && !Check(T.Eof))
|
while (!Check(T.ContextClose) && !Check(T.Eof))
|
||||||
Process();
|
Process();
|
||||||
Consume(T.ContextClose, "Expected '}' after context");
|
Consume(T.ContextClose, "Expected '}' after context");
|
||||||
|
|
@ -182,7 +200,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void WeightedDigest(Weight precedence)
|
internal void WeightedDigest(Weight precedence)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Next();
|
Next();
|
||||||
Rule rule = ExpressionParser.Get(Previous.Type);
|
Rule rule = ExpressionParser.Get(Previous.Type);
|
||||||
if (rule.Prefix == null) {
|
if (rule.Prefix == null) {
|
||||||
|
|
@ -204,7 +224,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void DeclareClass()
|
internal void DeclareClass()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.Identifier, "Expected a class name.");
|
Consume(T.Identifier, "Expected a class name.");
|
||||||
// we need both a global name constant and a local declaration for this class
|
// we need both a global name constant and a local declaration for this class
|
||||||
string name = Previous.Value!;
|
string name = Previous.Value!;
|
||||||
|
|
@ -250,7 +272,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void DeclareFunction()
|
internal void DeclareFunction()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
long global = ParseVariable();
|
long global = ParseVariable();
|
||||||
InitializeLocal();
|
InitializeLocal();
|
||||||
CreateFunction(FunctionType.Function);
|
CreateFunction(FunctionType.Function);
|
||||||
|
|
@ -260,7 +284,9 @@ public class Digester : ISteppable<Token>
|
||||||
internal void DeclareMember()
|
internal void DeclareMember()
|
||||||
{
|
{
|
||||||
// todo: only methods allowed atm, add fields and shit too
|
// todo: only methods allowed atm, add fields and shit too
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.Identifier, "Expected method name.", false);
|
Consume(T.Identifier, "Expected method name.", false);
|
||||||
long identifier = IdentifierConstant(Previous.Value!);
|
long identifier = IdentifierConstant(Previous.Value!);
|
||||||
FunctionType type = FunctionType.Method;
|
FunctionType type = FunctionType.Method;
|
||||||
|
|
@ -272,7 +298,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void DeclareVariable()
|
internal void DeclareVariable()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
long global = ParseVariable();
|
long global = ParseVariable();
|
||||||
if (Match(T.Equal))
|
if (Match(T.Equal))
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
|
|
@ -284,19 +312,25 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Export()
|
internal void Export()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult.");
|
throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult.");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Import()
|
internal void Import()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult.");
|
throw new NotImplementedException($"Import is not yet implemented. Sorry, it's difficult.");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void If()
|
internal void If()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.GroupOpen, "Expected '(' after if");
|
Consume(T.GroupOpen, "Expected '(' after if");
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
Consume(T.GroupClose, "Expected ')' after condition");
|
Consume(T.GroupClose, "Expected ')' after condition");
|
||||||
|
|
@ -318,13 +352,17 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Else()
|
internal void Else()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
ErrorAtPrevious("This 'else' is very alone :( Have you meant to place it after an 'if'?");
|
ErrorAtPrevious("This 'else' is very alone :( Have you meant to place it after an 'if'?");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void While()
|
internal void While()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
long start = Function.CurrentInstruction;
|
long start = Function.CurrentInstruction;
|
||||||
Consume(T.GroupOpen, "Expected while condition to be placed inside parentheses. Missing '('.", false);
|
Consume(T.GroupOpen, "Expected while condition to be placed inside parentheses. Missing '('.", false);
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
|
|
@ -339,14 +377,18 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Do()
|
internal void Do()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
// todo: just do a while loop here with synthetic counter variables checked at end
|
// todo: just do a while loop here with synthetic counter variables checked at end
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void For()
|
internal void For()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
BeginScope();
|
BeginScope();
|
||||||
Consume(T.GroupOpen, "Expected '(' after for statement");
|
Consume(T.GroupOpen, "Expected '(' after for statement");
|
||||||
if (Match(T.Semicolon)) {
|
if (Match(T.Semicolon)) {
|
||||||
|
|
@ -390,7 +432,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Return()
|
internal void Return()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
if (Builder.Type == FunctionType.Code) {
|
if (Builder.Type == FunctionType.Code) {
|
||||||
ErrorAtPrevious($"Interesting approach, but that won't work.");
|
ErrorAtPrevious($"Interesting approach, but that won't work.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -412,7 +456,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void Print()
|
internal void Print()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
Consume(T.Semicolon, "Expected ';' after print call.");
|
Consume(T.Semicolon, "Expected ';' after print call.");
|
||||||
Emit(Op.Print);
|
Emit(Op.Print);
|
||||||
|
|
@ -420,41 +466,53 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void PrintGlobals()
|
internal void PrintGlobals()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.Semicolon, "Expected ';' after print call.");
|
Consume(T.Semicolon, "Expected ';' after print call.");
|
||||||
Emit(Op.PrintGlobals);
|
Emit(Op.PrintGlobals);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void PrintStack()
|
internal void PrintStack()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.Semicolon, "Expected ';' after print call.");
|
Consume(T.Semicolon, "Expected ';' after print call.");
|
||||||
Emit(Op.PrintStack);
|
Emit(Op.PrintStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void PrintExpr()
|
internal void PrintExpr()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Consume(T.Semicolon, "Expected ';' after print call.");
|
Consume(T.Semicolon, "Expected ';' after print call.");
|
||||||
Emit(Op.PrintExpr);
|
Emit(Op.PrintExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void TypeOf()
|
internal void TypeOf()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
ParseExpression();
|
ParseExpression();
|
||||||
Emit(Op.Typeof);
|
Emit(Op.Typeof);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void BeginScope()
|
internal void BeginScope()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Builder.ScopeDepth++;
|
Builder.ScopeDepth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void EndScope()
|
internal void EndScope()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Builder.ScopeDepth--;
|
Builder.ScopeDepth--;
|
||||||
while (Builder.Locals.Count > 0 &&
|
while (Builder.Locals.Count > 0 &&
|
||||||
Builder.Locals.Peek().Depth > Builder.ScopeDepth) {
|
Builder.Locals.Peek().Depth > Builder.ScopeDepth) {
|
||||||
|
|
@ -469,7 +527,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void CreateFunction(FunctionType type)
|
internal void CreateFunction(FunctionType type)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Builder next = CreateBuilder(type);
|
Builder next = CreateBuilder(type);
|
||||||
BeginScope();
|
BeginScope();
|
||||||
Consume(T.GroupOpen, "Expected '(' to start argument list.");
|
Consume(T.GroupOpen, "Expected '(' to start argument list.");
|
||||||
|
|
@ -506,7 +566,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void AddLocal(string? name)
|
internal void AddLocal(string? name)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(name);
|
_logger.Method(name);
|
||||||
|
#endif
|
||||||
Builder.Locals.Push(new Local(ThrowIfEmpty(name), -1));
|
Builder.Locals.Push(new Local(ThrowIfEmpty(name), -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -515,7 +577,9 @@ public class Digester : ISteppable<Token>
|
||||||
if (Builder.ScopeDepth == 0)
|
if (Builder.ScopeDepth == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
_logger.Method(name);
|
_logger.Method(name);
|
||||||
|
#endif
|
||||||
for (int i = 0; i < Builder.Locals.Count; i++) {
|
for (int i = 0; i < Builder.Locals.Count; i++) {
|
||||||
Local local = Builder.Locals[i];
|
Local local = Builder.Locals[i];
|
||||||
// skip if the most recent local isn't even in our scope
|
// skip if the most recent local isn't even in our scope
|
||||||
|
|
@ -562,22 +626,30 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal long IdentifierConstant(string? name)
|
internal long IdentifierConstant(string? name)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(name);
|
_logger.Method(name);
|
||||||
|
#endif
|
||||||
return MakeConstant(String.Make(name ??
|
return MakeConstant(String.Make(name ??
|
||||||
throw new TokenException("Empty string value for identifier detected", _reader, Current)));
|
throw new TokenException("Empty string value for identifier detected", _reader, Current)));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal long MakeConstant(Value value)
|
internal long MakeConstant(Value value)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(value.ToString());
|
_logger.Method(value.ToString());
|
||||||
|
#endif
|
||||||
long constant = Function.Segment.Constants.Add(value);
|
long constant = Function.Segment.Constants.Add(value);
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"Registered constant {value} at index {constant}");
|
_logger.Verbose($"Registered constant {value} at index {constant}");
|
||||||
|
#endif
|
||||||
return constant;
|
return constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal long ParseVariable()
|
internal long ParseVariable()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
string? name = Consume(T.Identifier, "Missing identifier for variable").Value;
|
string? name = Consume(T.Identifier, "Missing identifier for variable").Value;
|
||||||
if (Builder.ScopeDepth == 0)
|
if (Builder.ScopeDepth == 0)
|
||||||
return IdentifierConstant(name);
|
return IdentifierConstant(name);
|
||||||
|
|
@ -590,7 +662,9 @@ public class Digester : ISteppable<Token>
|
||||||
if (Builder.ScopeDepth == 0)
|
if (Builder.ScopeDepth == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
var local = Builder.Locals.Peek();
|
var local = Builder.Locals.Peek();
|
||||||
local.Depth = Builder.ScopeDepth;
|
local.Depth = Builder.ScopeDepth;
|
||||||
Builder.Locals.Set(Builder.Locals.Position - 1, local);
|
Builder.Locals.Set(Builder.Locals.Position - 1, local);
|
||||||
|
|
@ -598,7 +672,9 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
internal void DefineVariable(long index)
|
internal void DefineVariable(long index)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(index.ToString());
|
_logger.Method(index.ToString());
|
||||||
|
#endif
|
||||||
if (Builder.ScopeDepth > 0) {
|
if (Builder.ScopeDepth > 0) {
|
||||||
InitializeLocal();
|
InitializeLocal();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -627,10 +703,12 @@ public class Digester : ISteppable<Token>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void Emit(params byte[] data)
|
internal void Emit(params byte[] data)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
if (data.Length == 1)
|
if (data.Length == 1)
|
||||||
_logger.Verbose($"Emitting {new Instruction(data[0])}");
|
_logger.Verbose($"Emitting {new Instruction(data[0])}");
|
||||||
else if (data.Length > 1)
|
else if (data.Length > 1)
|
||||||
_logger.Verbose($"Emitting {string.Join(' ', data)}");
|
_logger.Verbose($"Emitting {string.Join(' ', data)}");
|
||||||
|
#endif
|
||||||
foreach (var value in data)
|
foreach (var value in data)
|
||||||
Function.Segment.Instructions.Add(value);
|
Function.Segment.Instructions.Add(value);
|
||||||
}
|
}
|
||||||
|
|
@ -778,9 +856,13 @@ public class Digester : ISteppable<Token>
|
||||||
|
|
||||||
private void ReportError(Token token, string errorMessage)
|
private void ReportError(Token token, string errorMessage)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
ErrorPosition = token.Position;
|
ErrorPosition = token.Position;
|
||||||
|
#if LOG
|
||||||
_logger.Error($"At token index {token.Position}: {errorMessage}");
|
_logger.Error($"At token index {token.Position}: {errorMessage}");
|
||||||
|
#endif
|
||||||
if (ThrowOnError)
|
if (ThrowOnError)
|
||||||
throw new TokenException($"At token index {token.Position}: {errorMessage}", _reader, token);
|
throw new TokenException($"At token index {token.Position}: {errorMessage}", _reader, token);
|
||||||
Error?.Invoke(token, errorMessage);
|
Error?.Invoke(token, errorMessage);
|
||||||
|
|
|
||||||
|
|
@ -114,16 +114,16 @@ public static class ExpressionParser
|
||||||
static void ArrayAdd(Digester digester, bool canAssign)
|
static void ArrayAdd(Digester digester, bool canAssign)
|
||||||
{
|
{
|
||||||
digester.ParseExpression();
|
digester.ParseExpression();
|
||||||
digester.Emit(OpCode.ArrayAdd);
|
digester.Emit(OpCode.AddItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Accessor(Digester digester, bool canAssign)
|
static void Accessor(Digester digester, bool canAssign)
|
||||||
{
|
{
|
||||||
digester.ParseExpression();
|
digester.ParseExpression();
|
||||||
digester.Consume(TokenType.ArrayClose, "expected ] after array accessor");
|
digester.Consume(TokenType.ArrayClose, "expected ] after array accessor");
|
||||||
if (canAssign && digester.Match(TokenType.ArrayAdd)) {
|
if (canAssign && digester.Match(TokenType.AddItem)) {
|
||||||
digester.ParseExpression();
|
digester.ParseExpression();
|
||||||
digester.Emit(OpCode.ArrayAdd);
|
digester.Emit(OpCode.AddItem);
|
||||||
} else if (canAssign && digester.Match(TokenType.Equal)) {
|
} else if (canAssign && digester.Match(TokenType.Equal)) {
|
||||||
digester.ParseExpression();
|
digester.ParseExpression();
|
||||||
digester.Emit(OpCode.SetItem);
|
digester.Emit(OpCode.SetItem);
|
||||||
|
|
@ -254,8 +254,8 @@ public static class ExpressionParser
|
||||||
_rules[TokenType.ContextClose] = new Rule(null, null, Weight.None);
|
_rules[TokenType.ContextClose] = new Rule(null, null, Weight.None);
|
||||||
_rules[TokenType.ArrayOpen] = new Rule(Array, Accessor, Weight.Call);
|
_rules[TokenType.ArrayOpen] = new Rule(Array, Accessor, Weight.Call);
|
||||||
_rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None);
|
_rules[TokenType.ArrayClose] = new Rule(null, null, Weight.None);
|
||||||
_rules[TokenType.ArrayAdd] = new Rule(null, ArrayAdd, Weight.None);
|
_rules[TokenType.AddItem] = new Rule(null, ArrayAdd, Weight.None);
|
||||||
_rules[TokenType.ArrayRemove] = new Rule(null, null, Weight.None);
|
_rules[TokenType.RemoveItem] = new Rule(null, null, Weight.None);
|
||||||
_rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call);
|
_rules[TokenType.Colon] = new Rule(null, Dot, Weight.Call);
|
||||||
_rules[TokenType.Comma] = new Rule(null, null, Weight.None);
|
_rules[TokenType.Comma] = new Rule(null, null, Weight.None);
|
||||||
_rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call);
|
_rules[TokenType.Dot] = new Rule(null, Dot, Weight.Call);
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,13 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
public ExecutionResult Run(Stream stream)
|
public ExecutionResult Run(Stream stream)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
if (Stack.Position < 0) {
|
if (Stack.Position < 0) {
|
||||||
|
#if LOG
|
||||||
_logger.Warn($"Something went wrong, stack cursor is at {Stack.Position}. Resetting Stack.");
|
_logger.Warn($"Something went wrong, stack cursor is at {Stack.Position}. Resetting Stack.");
|
||||||
|
#endif
|
||||||
Stack.Decimate(0);
|
Stack.Decimate(0);
|
||||||
}
|
}
|
||||||
using Reader reader = new Reader(stream);
|
using Reader reader = new Reader(stream);
|
||||||
|
|
@ -72,11 +76,15 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private ExecutionResult Execute()
|
private ExecutionResult Execute()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Call call = Calls.Peek(-1);
|
Call call = Calls.Peek(-1);
|
||||||
do {
|
do {
|
||||||
Op opCode = call.Instruction.Next();
|
Op opCode = call.Instruction.Next();
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"OpCode: {opCode}");
|
_logger.Verbose($"OpCode: {opCode}");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (TestFlag(opCode, Op.F_Operation)) {
|
if (TestFlag(opCode, Op.F_Operation)) {
|
||||||
Value result = ValueOperation.Resolve(PopOperation(opCode));
|
Value result = ValueOperation.Resolve(PopOperation(opCode));
|
||||||
|
|
@ -105,7 +113,9 @@ public class Runner : IDisposable
|
||||||
Push(Value.Void);
|
Push(Value.Void);
|
||||||
else
|
else
|
||||||
Push(Globals[name]);
|
Push(Globals[name]);
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"got global {name} ({Peek()})");
|
_logger.Verbose($"got global {name} ({Peek()})");
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +126,9 @@ public class Runner : IDisposable
|
||||||
if (!Globals.Has(name))
|
if (!Globals.Has(name))
|
||||||
return Error($"tried to set a value of non-existing global variable");
|
return Error($"tried to set a value of non-existing global variable");
|
||||||
Globals[name] = Pop();
|
Globals[name] = Pop();
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"set global {name} = {Globals[name]}");
|
_logger.Verbose($"set global {name} = {Globals[name]}");
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,20 +137,26 @@ public class Runner : IDisposable
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
return Error($"tried to define global variable with empty name");
|
return Error($"tried to define global variable with empty name");
|
||||||
Globals[name] = Pop();
|
Globals[name] = Pop();
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"defined global {name} as {Globals[name]}");
|
_logger.Verbose($"defined global {name} as {Globals[name]}");
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Op.GetLocal: {
|
case Op.GetLocal: {
|
||||||
long slot = call.Instruction.NextDynamic();
|
long slot = call.Instruction.NextDynamic();
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"getting slot {slot} which is {call.StackPtr.Get(slot)}");
|
_logger.Verbose($"getting slot {slot} which is {call.StackPtr.Get(slot)}");
|
||||||
|
#endif
|
||||||
Push(call.StackPtr.Get(slot));
|
Push(call.StackPtr.Get(slot));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Op.SetLocal: {
|
case Op.SetLocal: {
|
||||||
long slot = call.Instruction.NextDynamic();
|
long slot = call.Instruction.NextDynamic();
|
||||||
|
#if LOG
|
||||||
_logger.Verbose($"setting stackptr {slot} to {Peek()}");
|
_logger.Verbose($"setting stackptr {slot} to {Peek()}");
|
||||||
|
#endif
|
||||||
call.StackPtr.Set(slot, Peek());
|
call.StackPtr.Set(slot, Peek());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -429,7 +447,9 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private bool InvokeNative(Value target, NativeExtension extension, int argumentCount)
|
private bool InvokeNative(Value target, NativeExtension extension, int argumentCount)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(extension);
|
_logger.Method(extension);
|
||||||
|
#endif
|
||||||
if (argumentCount != extension.Parameters.Length) {
|
if (argumentCount != extension.Parameters.Length) {
|
||||||
Error($"{extension} expects {extension.Parameters.Length} arguments, received {argumentCount}");
|
Error($"{extension} expects {extension.Parameters.Length} arguments, received {argumentCount}");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -448,7 +468,9 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private bool Invoke(Context closure, int argumentCount)
|
private bool Invoke(Context closure, int argumentCount)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
if (argumentCount != closure.Function.ArgumentCount) {
|
if (argumentCount != closure.Function.ArgumentCount) {
|
||||||
Error($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}");
|
Error($"Expected {closure.Function.ArgumentCount} arguments but got {argumentCount}");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -554,25 +576,33 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private Value Peek(int delta = -1)
|
private Value Peek(int delta = -1)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
return Stack.Peek(delta);
|
return Stack.Peek(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Value Pop()
|
private Value Pop()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
return Stack.Pop();
|
return Stack.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Push(Value value)
|
private void Push(Value value)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method($"{value}");
|
_logger.Method($"{value}");
|
||||||
|
#endif
|
||||||
Stack.Push(value);
|
Stack.Push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Operation PopOperation(Op code)
|
private Operation PopOperation(Op code)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(code);
|
_logger.Method(code);
|
||||||
|
#endif
|
||||||
if ((code & Op.F_Unary) == Op.F_Unary)
|
if ((code & Op.F_Unary) == Op.F_Unary)
|
||||||
return new Operation(code, Pop(), default);
|
return new Operation(code, Pop(), default);
|
||||||
Value right = Pop();
|
Value right = Pop();
|
||||||
|
|
@ -582,8 +612,12 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private ExecutionResult Error(string message, object? context = null, bool @throw = true)
|
private ExecutionResult Error(string message, object? context = null, bool @throw = true)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method(message);
|
_logger.Method(message);
|
||||||
|
#endif
|
||||||
|
#if LOG
|
||||||
_logger.Error(message, context);
|
_logger.Error(message, context);
|
||||||
|
#endif
|
||||||
Panic();
|
Panic();
|
||||||
if (@throw)
|
if (@throw)
|
||||||
throw new QampException(message, context);
|
throw new QampException(message, context);
|
||||||
|
|
@ -592,13 +626,17 @@ public class Runner : IDisposable
|
||||||
|
|
||||||
private void Panic()
|
private void Panic()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
Stack.Decimate(0);
|
Stack.Decimate(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method();
|
_logger.Method();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ public static class ValueOperation
|
||||||
|
|
||||||
public static Value Resolve(Operation operation)
|
public static Value Resolve(Operation operation)
|
||||||
{
|
{
|
||||||
|
#if LOG
|
||||||
_logger.Method($"{operation.Left} {operation.OpCode} {operation.Right}");
|
_logger.Method($"{operation.Left} {operation.OpCode} {operation.Right}");
|
||||||
|
#endif
|
||||||
return _operations[operation.OpCode].Invoke(operation);
|
return _operations[operation.OpCode].Invoke(operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +74,9 @@ public static class ValueOperation
|
||||||
public static Value Not(Operation operation)
|
public static Value Not(Operation operation)
|
||||||
{
|
{
|
||||||
Value value = operation.Left;
|
Value value = operation.Left;
|
||||||
|
#if LOG
|
||||||
_logger.Method($"{value}");
|
_logger.Method($"{value}");
|
||||||
|
#endif
|
||||||
Assert.NotVoid(value);
|
Assert.NotVoid(value);
|
||||||
ulong inner = value.Unsigned;
|
ulong inner = value.Unsigned;
|
||||||
return new Value(inner == 0);
|
return new Value(inner == 0);
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<BaseOutputPath>..\Build\</BaseOutputPath>
|
<BaseOutputPath>..\Build\</BaseOutputPath>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
|
<DefineConstants>DEV;XD</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ public class DefaultDialect : Dialect
|
||||||
Define(ContextClose, "}");
|
Define(ContextClose, "}");
|
||||||
Define(ArrayOpen, "[");
|
Define(ArrayOpen, "[");
|
||||||
Define(ArrayClose, "]");
|
Define(ArrayClose, "]");
|
||||||
Define(ArrayAdd, "<+");
|
Define(AddItem, "<+");
|
||||||
Define(ArrayRemove, "->");
|
Define(RemoveItem, "->");
|
||||||
Define(Comma, ",");
|
Define(Comma, ",");
|
||||||
Define(Dot, ".");
|
Define(Dot, ".");
|
||||||
Define(Colon, ":");
|
Define(Colon, ":");
|
||||||
|
|
@ -93,8 +93,8 @@ public class ClassicDialect : DefaultDialect
|
||||||
public ClassicDialect()
|
public ClassicDialect()
|
||||||
{
|
{
|
||||||
Define(Null, "_");
|
Define(Null, "_");
|
||||||
Define(ArrayAdd, "<+");
|
Define(AddItem, "<+");
|
||||||
Define(ArrayRemove, "->");
|
Define(RemoveItem, "->");
|
||||||
Define(Equal, "<~");
|
Define(Equal, "<~");
|
||||||
Define(This, ".~");
|
Define(This, ".~");
|
||||||
Define(Var, "*~");
|
Define(Var, "*~");
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,7 @@ public class Reader : IReader<Token>, IDisposable
|
||||||
Check(':') ?
|
Check(':') ?
|
||||||
MakeToken(Return, buffer + Next()) :
|
MakeToken(Return, buffer + Next()) :
|
||||||
Check('+') ?
|
Check('+') ?
|
||||||
MakeToken(ArrayAdd, buffer + Next()) :
|
MakeToken(AddItem, buffer + Next()) :
|
||||||
Check('<') ?
|
Check('<') ?
|
||||||
MakeToken(BitwiseLeft, buffer + Next()) :
|
MakeToken(BitwiseLeft, buffer + Next()) :
|
||||||
Check('=') ?
|
Check('=') ?
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ public enum TokenType
|
||||||
ArrayClose = Bracket | 6,
|
ArrayClose = Bracket | 6,
|
||||||
ListOpen = Bracket | 7,
|
ListOpen = Bracket | 7,
|
||||||
|
|
||||||
ArrayAdd,
|
AddItem,
|
||||||
ArrayRemove,
|
RemoveItem,
|
||||||
|
|
||||||
Comma,
|
Comma,
|
||||||
Dot,
|
Dot,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue