add while loop compilation and fix a few issues with execution
This commit is contained in:
parent
5d17059a7a
commit
ada9fc766e
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,7 @@ public class InstructionPtr : Pointer<Instruction>
|
||||||
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))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue