add while loop compilation and fix a few issues with execution

This commit is contained in:
Qrakhen 2025-11-07 14:40:56 +01:00
parent 5d17059a7a
commit ada9fc766e
4 changed files with 65 additions and 12 deletions

View File

@ -9,6 +9,8 @@ public class FunctionBuilder
public int OuterCount; public int OuterCount;
public int ArgumentCount; public int ArgumentCount;
public long CurrentInstruction => Segment.Instructions.Count;
public Function Build() public Function Build()
{ {
return new Function(Name, Segment.Build(), OuterCount, ArgumentCount); return new Function(Name, Segment.Build(), OuterCount, ArgumentCount);

View File

@ -183,12 +183,53 @@ public class Digester : ISteppable<Token>
} }
if (canAssign && Match(T.Equal)) if (canAssign && Match(T.Equal))
ErrorAtCurrent("Invalid assignment target"); ErrorAtCurrent("Invalid assignment target.");
} }
internal void DeclareClass() internal void DeclareClass()
{ {
_logger.Method(); _logger.Method();
Consume(T.Identifier, "Expected a class name.");
// we need both a global name constant and a local declaration for this class
string name = Previous.Value!;
long identifier = IdentifierConstant(name);
DeclareLocal(name);
EmitDynamic(Op.Class, identifier);
DefineVariable(identifier);
ClassBuilder = new ClassBuilder {
Outer = ClassBuilder,
Name = name,
IsDerived = false
};
if (Match(T.Colon))
{
Consume(T.Identifier, "Expected base class name.", false);
ExpressionParser.Variable(this, false);
if (name == Previous.Value!)
ErrorAtPrevious($"Class {name} can not inherit from itself!");
// Add base reference by injecting a synthetic base variable into a virtual scope
BeginScope();
AddLocal("base");
DefineVariable(0);
ExpressionParser.Variable(this, name, false);
ClassBuilder.IsDerived = true;
}
ExpressionParser.Variable(this, name, false);
Consume(T.ContextOpen, "Expected '{' for class body declaration.", false);
while (!Check(T.ContextClose) && !Check(T.Eof))
DeclareMethod();
Consume(T.ContextClose, "Expected '}' to end class body declaration.", false);
Emit(Op.Pop);
if (ClassBuilder.IsDerived)
EndScope();
ClassBuilder = ClassBuilder.Outer;
} }
internal void DeclareFunction() internal void DeclareFunction()
@ -203,13 +244,13 @@ public class Digester : ISteppable<Token>
internal void DeclareMethod() internal void DeclareMethod()
{ {
_logger.Method(); _logger.Method();
Consume(T.Identifier, "Expected method name", false); Consume(T.Identifier, "Expected method name.", false);
long name = IdentifierConstant(Previous.Value!); long identifier = IdentifierConstant(Previous.Value!);
FunctionType type = FunctionType.Method; FunctionType type = FunctionType.Method;
if (Previous.Value == ClassBuilder?.Name) if (Previous.Value == ClassBuilder?.Name)
type = FunctionType.Constructor; type = FunctionType.Constructor;
CreateFunction(type); CreateFunction(type);
EmitDynamic(Op.Method, name); EmitDynamic(Op.Method, identifier);
} }
internal void DeclareVariable() internal void DeclareVariable()
@ -259,17 +300,29 @@ public class Digester : ISteppable<Token>
internal void Else() internal void Else()
{ {
_logger.Method(); _logger.Method();
ErrorAtPrevious("Unexpected solitary 'else'"); ErrorAtPrevious("This 'else' is very alone :( Have you meant to place it after an 'if'?");
} }
internal void While() internal void While()
{ {
_logger.Method(); _logger.Method();
long start = Function.CurrentInstruction;
Consume(T.GroupOpen, "Expected while condition to be placed inside parentheses. Missing '('.", false);
Expression();
Consume(T.GroupClose, "Expected while condition to be placed inside parentheses. Missing ')'.", false);
long exit = EmitJump(Op.JumpIfFalse);
Emit(Op.Pop);
Statement();
EmitLoop(start);
PatchJump(exit);
Emit(Op.Pop);
} }
internal void Do() internal void Do()
{ {
_logger.Method(); _logger.Method();
// todo: just do a while loop here with synthetic counter variables checked at end
throw new NotImplementedException();
} }
internal void For() internal void For()
@ -285,7 +338,7 @@ public class Digester : ISteppable<Token>
StatementExpression(); StatementExpression();
} }
long start = Function.Segment.Instructions.Count; long start = Function.CurrentInstruction;
long exit = -1; long exit = -1;
if (!Match(T.Semicolon)) { if (!Match(T.Semicolon)) {
Expression(); Expression();

View File

@ -166,7 +166,7 @@ public static class ExpressionParser
digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value)); digester.EmitConstant(Values.Objects.String.Make(digester.Previous.Value));
} }
static void Variable(Digester digester, string name, bool canAssign) public static void Variable(Digester digester, string name, bool canAssign)
{ {
OpCode Get, Set; OpCode Get, Set;
long variable = digester.ResolveLocal(digester.Builder, name); long variable = digester.ResolveLocal(digester.Builder, name);
@ -192,7 +192,7 @@ public static class ExpressionParser
} }
} }
static void Variable(Digester digester, bool canAssign) public static void Variable(Digester digester, bool canAssign)
{ {
Variable(digester, digester.Previous.Value!, canAssign); Variable(digester, digester.Previous.Value!, canAssign);
} }

View File

@ -61,10 +61,8 @@ public class InstructionPtr : Pointer<Instruction>
int length = Segment.Read(Ptr) ^ 0x80; int length = Segment.Read(Ptr) ^ 0x80;
Ptr++; Ptr++;
byte[] data = new byte[8]; byte[] data = new byte[8];
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{
data[i] = Segment.Read(Ptr++); data[i] = Segment.Read(Ptr++);
}
return data.ToInt64(); return data.ToInt64();
} }
@ -211,7 +209,7 @@ public class Runner : IDisposable
// todo: add closure // todo: add closure
case Op.GetGlobal: { case Op.GetGlobal: {
string? name = call.Ptr.GetString(call.Ptr.NextLong())?.Value; string? name = call.Ptr.GetString(call.Ptr.NextDynamic())?.Value;
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
throw new ExecutionException($"tried to set global variable with empty name"); throw new ExecutionException($"tried to set global variable with empty name");
if (!Globals.Has(name)) if (!Globals.Has(name))