Skip to content

Commit

Permalink
#31 - remove IR from codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
Stepami committed Jul 27, 2024
1 parent 27ef52a commit 69dd6e1
Show file tree
Hide file tree
Showing 16 changed files with 69 additions and 67 deletions.
11 changes: 3 additions & 8 deletions src/HydraScript.Lib/BackEnd/Call.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@
namespace HydraScript.Lib.BackEnd;

public record Call(
IAddress From, FunctionInfo To,
List<CallArgument> Arguments,
IAddress From,
FunctionInfo To,
string? Where = null)
{
public override string ToString() =>
$"{From} => {To.Start}: {To.Id}({string.Join(", ", Arguments)})";
}

public record CallArgument(string Id, object? Value)
{
public override string ToString() => $"{Id}: {Value}";
$"{From}: {Where} => {To.Start}: {To.Id}";
}

public record FunctionInfo(string Id)
Expand Down
2 changes: 1 addition & 1 deletion src/HydraScript.Lib/BackEnd/IExecuteParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ public interface IExecuteParams
{
public Stack<Call> CallStack { get; }
public Stack<Frame> Frames { get; }
public Stack<CallArgument> Arguments { get; }
public Queue<object?> Arguments { get; }
public TextWriter Writer { get; }
}
2 changes: 1 addition & 1 deletion src/HydraScript.Lib/BackEnd/Impl/ExecuteParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ public class ExecuteParams(TextWriter textWriter) : IExecuteParams
{
public Stack<Call> CallStack { get; } = new();
public Stack<Frame> Frames { get; } = new();
public Stack<CallArgument> Arguments { get; } = new();
public Queue<object?> Arguments { get; } = new();
public TextWriter Writer { get; } = textWriter;
}
14 changes: 14 additions & 0 deletions src/HydraScript.Lib/BackEnd/Impl/Instructions/PopParameter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace HydraScript.Lib.BackEnd.Impl.Instructions;

public class PopParameter(string parameter) : Instruction
{
public override IAddress Execute(IExecuteParams executeParams)
{
var argument = executeParams.Arguments.Dequeue();
executeParams.Frames.Peek()[parameter] = argument;
return Address.Next;
}

protected override string ToStringInternal() =>
$"PopParameter {parameter}";
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
namespace HydraScript.Lib.BackEnd.Impl.Instructions;

public class PushParameter(string parameter, IValue value) : Instruction
public class PushParameter(IValue value) : Instruction
{
public override IAddress Execute(IExecuteParams executeParams)
{
executeParams.Arguments.Push(new CallArgument(
parameter,
value.Get(executeParams.Frames.Peek())));
executeParams.Arguments.Enqueue(
value.Get(executeParams.Frames.Peek()));
return Address.Next;
}

protected override string ToStringInternal() =>
$"PushParameter {parameter} = {value}";
$"PushParameter {value}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ namespace HydraScript.Lib.BackEnd.Impl.Instructions.WithAssignment;

public class CallFunction(
FunctionInfo function,
int numberOfArguments,
bool hasReturnValue) : Simple(null, (null, null), "Call ")
{
protected override void OnSetOfAddress(IAddress address)
Expand All @@ -14,22 +13,12 @@ protected override void OnSetOfAddress(IAddress address)
public override IAddress Execute(IExecuteParams executeParams)
{
var frame = new Frame(Address.Next, executeParams.Frames.Peek());

var i = 0;
var args = new List<CallArgument>();
while (i < numberOfArguments)
{
args.Add(executeParams.Arguments.Pop());
frame[args[i].Id] = args[i].Value;
i++;
}

executeParams.CallStack.Push(new Call(Address, function, args, Left));
executeParams.CallStack.Push(new Call(Address, function, Left));
executeParams.Frames.Push(frame);
return function.Start;
}

protected override string ToStringInternal() => Left == null
? $"Call {function}, {numberOfArguments}"
: $"{Left} = Call {function}, {numberOfArguments}";
? $"Call {function}"
: $"{Left} = Call {function}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public partial class FunctionDeclaration : AfterTypesAreLoadedDeclaration
public IReadOnlyList<PropertyTypeValue> Arguments => _arguments;

public BlockStatement Statements { get; }
public bool IsEmpty => Statements.Count == 0;

public FunctionDeclaration(
IdentifierReference name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public partial class CallExpression : LeftHandSideExpression
public MemberExpression Member { get; }
public IReadOnlyList<Expression> Parameters => _parameters;

public bool IsEmptyCall { get; set; }
public bool HasReturnValue { get; set; }

public CallExpression(MemberExpression member, IEnumerable<Expression> expressions)
{
Member = member;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals;
using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions;
using HydraScript.Lib.IR.Ast.Visitors.Services;
using HydraScript.Lib.IR.CheckSemantics.Variables.Impl.Symbols;

namespace HydraScript.Lib.IR.Ast.Visitors;

Expand Down Expand Up @@ -261,6 +260,8 @@ public AddressedInstructions Visit(IndexAccess visitable)

public AddressedInstructions Visit(CallExpression visitable)
{
if (visitable.IsEmptyCall)
return [];
var methodCall = !visitable.Empty();
if (visitable.Id.Name is "print" && !methodCall)
{
Expand All @@ -277,7 +278,7 @@ public AddressedInstructions Visit(CallExpression visitable)
}
else
{
FunctionSymbol functionSymbol;
string functionId;
AddressedInstructions result = [];
if (methodCall)
{
Expand All @@ -286,43 +287,34 @@ public AddressedInstructions Visit(CallExpression visitable)
memberInstructions.Remove(lastMemberInstruction);
result.AddRange(memberInstructions);

var methodName = lastMemberInstruction.Property;
functionSymbol = visitable.Scope
.FindSymbol<FunctionSymbol>(methodName)!;
functionId = lastMemberInstruction.Property;
}
else
{
functionSymbol = visitable.Scope
.FindSymbol<FunctionSymbol>(visitable.Id)!;
functionId = visitable.Id;
}
if (functionSymbol.IsEmpty)
return [];
var functionInfo = new FunctionInfo(functionSymbol.Id);
var functionInfo = new FunctionInfo(functionId);

if (methodCall)
{
var caller = result.Any() ? result.OfType<Simple>().Last().Left! : visitable.Id;
result.Add(new PushParameter(functionSymbol.Parameters[0].Id, new Name(caller)));
result.Add(new PushParameter(new Name(caller)));
}
foreach (var (expr, symbol) in visitable.Parameters
.Zip(functionSymbol.Parameters.ToArray()[(methodCall ? 1 : 0)..]))
foreach (var expr in visitable.Parameters)
{
if (expr is PrimaryExpression primary)
result.Add(new PushParameter(symbol.Id, _valueDtoConverter.Convert(primary.ToValueDto())));
result.Add(new PushParameter(_valueDtoConverter.Convert(primary.ToValueDto())));
else
{
result.AddRange(expr.Accept(This));
var id = result.OfType<Simple>().Last().Left!;
result.Add(new PushParameter(symbol.Id, new Name(id)));
result.Add(new PushParameter(new Name(id)));
}
}

Type @void = "void";
var hasReturnValue = !functionSymbol.Type.Equals(@void);
result.Add(new CallFunction(
functionInfo,
numberOfArguments: visitable.Parameters.Count + (methodCall ? 1 : 0),
hasReturnValue));
visitable.HasReturnValue));
return result;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/HydraScript.Lib/IR/Ast/Visitors/InstructionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ public AddressedInstructions Visit(FunctionDeclaration visitable)
}
};

foreach (var (id, _) in visitable.Arguments)
result.Add(new PopParameter(id));

result.AddRange(visitable.Statements.Accept(This));
if (!visitable.HasReturnStatement())
result.Add(new Return());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public VisitUnit Visit(FunctionDeclaration visitable)
visitable.Name,
parameters,
visitable.ReturnTypeValue.Accept(_typeBuilder),
isEmpty: !visitable.Statements.Any());
visitable.IsEmpty);
if (parameters is [{ Type: ObjectType objectType }, ..] &&
visitable.Arguments is [{ TypeValue: TypeIdentValue }, ..])
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ symbol as FunctionSymbol
?? throw new SymbolIsNotCallable(symbol.Id, visitable.Id.Segment);
}

visitable.IsEmptyCall = functionSymbol.IsEmpty;
var functionReturnType = functionSymbol.Type;

if (functionSymbol.Parameters.Count != visitable.Parameters.Count + (methodCall ? 1 : 0))
Expand All @@ -422,6 +423,9 @@ symbol as FunctionSymbol
functionReturnType = declaration.Accept(This);
}

Type @void = "void";
if (functionReturnType.Equals(@void))
visitable.HasReturnValue = true;
return functionReturnType;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ public ISymbolTable GetStandardLibrary()
var library = new SymbolTable();

foreach (var type in _provider.GetDefaultTypes())
{
library.AddSymbol(new TypeSymbol(type));
}

var print = new FunctionSymbol(
"print",
[new VariableSymbol("str", "string")],
"void",
isEmpty: false
);
isEmpty: false);

library.AddSymbol(print);

Expand Down
17 changes: 11 additions & 6 deletions tests/HydraScript.Tests/TestData/InstructionsData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ public IEnumerator<object[]> GetEnumerator()
};
yield return new object[]
{
new CallFunction(new FunctionInfo("func"), 2, false),
"Call func, 2"
new CallFunction(new FunctionInfo("func"), false),
"Call func"
};
yield return new object[]
{
new CallFunction(new FunctionInfo("func"), 2, true)
new CallFunction(new FunctionInfo("func"), true)
{
Left = "ret"
},
"ret = Call func, 2"
"ret = Call func"
};
yield return new object[]
{
Expand Down Expand Up @@ -93,8 +93,13 @@ public IEnumerator<object[]> GetEnumerator()
};
yield return new object[]
{
new PushParameter("param", new Name("value")),
"PushParameter param = value"
new PushParameter(new Name("value")),
"PushParameter value"
};
yield return new object[]
{
new PopParameter("param"),
"PopParameter param"
};
yield return new object[]
{
Expand Down
5 changes: 2 additions & 3 deletions tests/HydraScript.Tests/Unit/BackEnd/CallTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ public void ToStringCorrect()
{
var call = new Call(
new Label("9"),
new FunctionInfo("func"),
[new CallArgument("arg", 1)]);
const string expected = "9:\n\t => Start_func:\n\t: func(arg: 1)";
new FunctionInfo("func"));
const string expected = "9:\n\t: => Start_func:\n\t: func";
Assert.Equal(expected, call.ToString());
}
}
11 changes: 6 additions & 5 deletions tests/HydraScript.Tests/Unit/BackEnd/VirtualMachineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void CorrectPrintToOutTest()
var exParams = new Mock<IExecuteParams>();
exParams.Setup(x => x.CallStack).Returns(new Stack<Call>());
exParams.Setup(x => x.Frames).Returns(new Stack<Frame>(new[] { new Frame(new HashAddress(0)) }));
exParams.Setup(x => x.Arguments).Returns(new Stack<CallArgument>());
exParams.Setup(x => x.Arguments).Returns(new Queue<object?>());
exParams.Setup(x => x.Writer).Returns(writer.Object);

var print = new Print(new Constant(223))
Expand Down Expand Up @@ -82,20 +82,21 @@ public void VirtualMachineHandlesRecursionTest()
{
new Goto(factorial.End),
{ new BeginBlock(BlockType.Function, blockId: factorial.ToString()), factorial.Start.Name },
new PopParameter("n"),
new Simple("_t2", (new Name("n"), new Constant(2)), "<"),
new IfNotGoto(new Name("_t2"), new Label("5")),
new Return(new Name("n")),
{ new Simple("_t5", (new Name("n"), new Constant(1)), "-"), "5" },
new PushParameter("n", new Name("_t5")),
new CallFunction(factorial, 1, true)
new PushParameter(new Name("_t5")),
new CallFunction(factorial, true)
{
Left = "f"
},
new Simple("_t8", (new Name("n"), new Name("f")), "*"),
new Return(new Name("_t8")),
{ new EndBlock(BlockType.Function, blockId: factorial.ToString()), factorial.End.Name },
new PushParameter("n", new Constant(6)),
new CallFunction(factorial, 1, true)
new PushParameter(new Constant(6)),
new CallFunction(factorial, true)
{
Left = "fa6"
},
Expand Down

0 comments on commit 69dd6e1

Please sign in to comment.