Skip to content

Commit

Permalink
Новая система адресации инструкций (#21)
Browse files Browse the repository at this point in the history
* initial of the branch

* контракт адреса

* Переезд на .NET 7 (#24)

* обновление sdk в проекте

* обновление sdk в ci

* переход на json raw string literal

* обновление nuget пакетов

* Генерация отчёта о покрытии на уровне конфигурации проекта

coverlet-coverage/coverlet#1391

* Генерация отчёта о покрытии на уровне конфигурации проекта

coverlet-coverage/coverlet#1391

* versioning

* Update Readme.md

* draft алгоритма работы коллекции

* Использование последних наворотов шарпа (#26)

* versioning

* enabling implicit usings (#25)

* local scoped namespaces (#27)

* after merge

* разработка алгоритма вставки в коллекцию

* пакетная вставка

* доработка алгоритма вставки

* индексатор

* прямая итерация над коллекцией

* важная доработка вставки - сгенерированный адрес проставляется инструкции, больше не требуется создавать адрес для создания инструкции

* переименовал сущность адреса

* доработка массовой вставки

* алгоритм удаления инструкции

* unit tests

* more tests
  • Loading branch information
Stepami authored Dec 23, 2022
1 parent a988279 commit a3314ab
Show file tree
Hide file tree
Showing 159 changed files with 4,767 additions and 4,845 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
dotnet-version: 7.0.x
- name: Cache NuGet packages
uses: actions/cache@v3
with:
Expand All @@ -30,7 +30,7 @@ jobs:
run: dotnet build --no-restore -c Release -v n
- name: Test
run: |
dotnet test -c Release --no-build -v n /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --filter="Category=Unit"
dotnet test -c Release --no-build -v n --filter="Category=Unit"
mkdir coverage-report
- name: Code Coverage Summary Report For Merge Request
if: github.event_name == 'pull_request'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
dotnet-version: 7.0.x
- name: Publish
run: |
mkdir output
Expand Down
69 changes: 69 additions & 0 deletions Interpreter.Lib/BackEnd/AddressedInstructions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Collections;
using Interpreter.Lib.BackEnd.Addresses;
using Interpreter.Lib.BackEnd.Instructions;

namespace Interpreter.Lib.BackEnd;

public class AddressedInstructions : IEnumerable<Instruction>
{
private readonly LinkedList<IAddress> _addresses = new();
private readonly Dictionary<IAddress, LinkedListNode<IAddress>> _addressToNode = new();
private readonly Dictionary<LinkedListNode<IAddress>, Instruction> _instructions = new();

public Instruction this[IAddress address] =>
_instructions[_addressToNode[address]];

public void Add(Instruction instruction, string label = null)
{
IAddress newAddress = label is null
? new HashedAddress(_addresses.Count, instruction.GetHashCode())
: new Label(label);
instruction.Address = newAddress;

var last = _addresses.Last;
if (last is not null)
last.Value.Next = newAddress;

var newNode = _addresses.AddLast(newAddress);

_addressToNode.Add(newAddress, newNode);
_instructions.Add(newNode, instruction);
}

public void AddRange(IEnumerable<Instruction> instructions)
{
foreach (var instruction in instructions)
{
var strAddress = instruction.Address?.ToString();
Add(instruction,
strAddress != null &&
strAddress.StartsWith("address")
? null
: strAddress
);
}
}

public void Remove(Instruction instruction)
{
var address = instruction.Address;
var nodeToRemove = _addressToNode[address];

var prev = nodeToRemove.Previous;
if (prev is not null)
{
prev.Value.Next = nodeToRemove.Next?.Value;
}

_addressToNode.Remove(address);
_instructions.Remove(nodeToRemove);
_addresses.Remove(nodeToRemove);
}

public IEnumerator<Instruction> GetEnumerator() =>
_addresses.Select(address => this[address])
.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() =>
GetEnumerator();
}
31 changes: 31 additions & 0 deletions Interpreter.Lib/BackEnd/Addresses/HashedAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Interpreter.Lib.BackEnd.Addresses;

public class HashedAddress : IAddress
{
private readonly int _seed1, _seed2;

public IAddress Next { get; set; }

public HashedAddress(int seed1, int seed2) =>
(_seed1, _seed2) = (seed1, seed2);

public bool Equals(IAddress other)
{
if (other is HashedAddress simple)
return _seed1 == simple._seed1 &&
_seed2 == simple._seed2;

return false;
}

public override int GetHashCode()
{
var i1 = _seed1 ^ 17;
var i2 = 31 * _seed2 + i1;

return HashCode.Combine(i1, i2);
}

public override string ToString() =>
$"address{{{GetHashCode()}}}";
}
8 changes: 8 additions & 0 deletions Interpreter.Lib/BackEnd/Addresses/IAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Interpreter.Lib.BackEnd.Addresses;

public interface IAddress : IEquatable<IAddress>
{
IAddress Next { get; set; }

int GetHashCode();
}
24 changes: 24 additions & 0 deletions Interpreter.Lib/BackEnd/Addresses/Label.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Interpreter.Lib.BackEnd.Addresses;

public class Label : IAddress
{
private readonly string _name;

public Label(string name) =>
_name = name;

public IAddress Next { get; set; }

public bool Equals(IAddress other)
{
if (other is Label label)
return _name == label._name;

return false;
}

public override int GetHashCode() =>
_name.GetHashCode();

public override string ToString() => _name;
}
77 changes: 38 additions & 39 deletions Interpreter.Lib/BackEnd/Instructions/AsString.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,53 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using Interpreter.Lib.BackEnd.Values;
using SystemType = System.Type;

namespace Interpreter.Lib.BackEnd.Instructions
namespace Interpreter.Lib.BackEnd.Instructions;

public class AsString : Simple
{
public class AsString : Simple
public AsString(string left, IValue right, int number) :
base(left, (null, right), "", number)
{
public AsString(string left, IValue right, int number) :
base(left, (null, right), "", number)
{
}
}

public override int Execute(VirtualMachine vm)
{
var frame = vm.Frames.Peek();
frame[Left] = JsonSerializer.Serialize(
right.right.Get(frame),
new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles,
Converters = { new DoubleValueWriteConverter() },
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
}
);
public override int Execute(VirtualMachine vm)
{
var frame = vm.Frames.Peek();
frame[Left] = JsonSerializer.Serialize(
right.right.Get(frame),
new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReferenceHandler = ReferenceHandler.IgnoreCycles,
Converters = { new DoubleValueWriteConverter() },
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
}
);

return Jump();
}
return Jump();
}

protected override string ToStringRepresentation() => $"{Left} = {right.right} as string";
protected override string ToStringRepresentation() => $"{Left} = {right.right} as string";

[ExcludeFromCodeCoverage]
private class DoubleValueWriteConverter : JsonConverter<double>
{
public override double Read(ref Utf8JsonReader reader,
Type typeToConvert, JsonSerializerOptions options) =>
throw new NotImplementedException();
[ExcludeFromCodeCoverage]
private class DoubleValueWriteConverter : JsonConverter<double>
{
public override double Read(ref Utf8JsonReader reader,
SystemType typeToConvert, JsonSerializerOptions options) =>
throw new NotImplementedException();

public override void Write(Utf8JsonWriter writer,
double value, JsonSerializerOptions options)
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (value == Math.Truncate(value))
writer.WriteNumberValue(Convert.ToInt64(value));
else
writer.WriteNumberValue(value);
}
public override void Write(Utf8JsonWriter writer,
double value, JsonSerializerOptions options)
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (value == Math.Truncate(value))
writer.WriteNumberValue(Convert.ToInt64(value));
else
writer.WriteNumberValue(value);
}
}
}
21 changes: 10 additions & 11 deletions Interpreter.Lib/BackEnd/Instructions/BeginFunction.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
namespace Interpreter.Lib.BackEnd.Instructions
namespace Interpreter.Lib.BackEnd.Instructions;

public class BeginFunction : Instruction
{
public class BeginFunction : Instruction
{
private readonly FunctionInfo _function;
private readonly FunctionInfo _function;

public BeginFunction(int number, FunctionInfo function) : base(number)
{
_function = function;
}
public BeginFunction(int number, FunctionInfo function) : base(number)
{
_function = function;
}

public override int Execute(VirtualMachine vm) => Number + 1;
public override int Execute(VirtualMachine vm) => Number + 1;

protected override string ToStringRepresentation() => $"BeginFunction {_function.CallId()}";
}
protected override string ToStringRepresentation() => $"BeginFunction {_function.CallId()}";
}
72 changes: 34 additions & 38 deletions Interpreter.Lib/BackEnd/Instructions/CallFunction.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,47 @@
using System;
using System.Collections.Generic;
namespace Interpreter.Lib.BackEnd.Instructions;

namespace Interpreter.Lib.BackEnd.Instructions
public class CallFunction : Simple
{
public class CallFunction : Simple
{
private readonly FunctionInfo _function;
private readonly int _numberOfArguments;
private readonly FunctionInfo _function;
private readonly int _numberOfArguments;

public CallFunction(FunctionInfo function, int number, int numberOfArguments, string left = null) :
base(left, (null, null), "Call ", number)
{
_function = function;
_numberOfArguments = numberOfArguments + Convert.ToInt32(function.MethodOf != null);
}
public CallFunction(FunctionInfo function, int number, int numberOfArguments, string left = null) :
base(left, (null, null), "Call ", number)
{
_function = function;
_numberOfArguments = numberOfArguments + Convert.ToInt32(function.MethodOf != null);
}

public override int Jump() => _function.Location;
public override int Jump() => _function.Location;

public override int Execute(VirtualMachine vm)
{
var frame = new Frame(Number + 1, vm.Frames.Peek());
public override int Execute(VirtualMachine vm)
{
var frame = new Frame(Number + 1, vm.Frames.Peek());

var i = 0;
var args = new List<(string Id, object Value)>();
while (i < _numberOfArguments)
{
args.Add(vm.Arguments.Pop());
frame[args[i].Id] = args[i].Value;
i++;
}
var i = 0;
var args = new List<(string Id, object Value)>();
while (i < _numberOfArguments)
{
args.Add(vm.Arguments.Pop());
frame[args[i].Id] = args[i].Value;
i++;
}

if (_function.MethodOf != null)
if (_function.MethodOf != null)
{
var obj = (Dictionary<string, object>) frame[_function.MethodOf];
foreach (var (key, value) in obj)
{
var obj = (Dictionary<string, object>) frame[_function.MethodOf];
foreach (var (key, value) in obj)
{
frame[key] = value;
}
frame[key] = value;
}

vm.CallStack.Push(new Call(Number, _function, args, Left));
vm.Frames.Push(frame);
return _function.Location;
}

protected override string ToStringRepresentation() => Left == null
? $"Call {_function}, {_numberOfArguments}"
: $"{Left} = Call {_function}, {_numberOfArguments}";
vm.CallStack.Push(new Call(Number, _function, args, Left));
vm.Frames.Push(frame);
return _function.Location;
}

protected override string ToStringRepresentation() => Left == null
? $"Call {_function}, {_numberOfArguments}"
: $"{Left} = Call {_function}, {_numberOfArguments}";
}
Loading

0 comments on commit a3314ab

Please sign in to comment.