Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ImportLocation to SymbolToken #12

Merged
merged 5 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions IonDotnet.Tests/Common/SymTabUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ internal static void AssertSymbolInTable(string text, int sid, bool duplicate, I

Assert.AreEqual(sid, symbolTable.FindSymbolId(text));
var token = symbolTable.Find(text);
Assert.AreEqual(sid, token.Sid);
Assert.AreEqual(SymbolToken.UnknownSid, token.Sid);
Assert.AreEqual(text, token.Text);

token = symbolTable.Intern(text);
Assert.AreEqual(sid, token.Sid);
Assert.AreEqual(SymbolToken.UnknownSid, token.Sid);
Assert.AreEqual(text, token.Text);
}
}
Expand Down
48 changes: 48 additions & 0 deletions IonDotnet.Tests/Internals/ImportLocationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace IonDotnet.Tests.Internals
{
[TestClass]
public class ImportLocationTest
{
[TestMethod]
public void Init_SidAndTextUnknown()
{
var location = new ImportLocation();
Assert.AreEqual(null, location.ImportName);
Assert.AreEqual(0, location.Sid);
}

[TestMethod]
[DataRow("text1", 123, "text1", 123)]
[DataRow("text2", 456, "text2", 456)]
public void Bool_EqualsOperator(string text1, int sid1, string text2, int sid2)
{
var location1 = new ImportLocation(text1, sid1);
var location2 = new ImportLocation(text2, sid2);
Assert.IsTrue(location1 == location2);
}

[TestMethod]
[DataRow("text1", 123, "text1", 456)]
[DataRow("text2", 456, "text3", 456)]
public void Bool_NotEqualsOperator(string text1, int sid1, string text2, int sid2)
{
var location1 = new ImportLocation(text1, sid1);
var location2 = new ImportLocation(text2, sid2);
Assert.IsTrue(location1 != location2);
}

[TestMethod]
public void EqualsMethod()
{
var location = CreateSampleToken();
var equalLocation = new ImportLocation("yo", 30);
var unEqualLocation = new ImportLocation("yo", 31);
Assert.IsTrue(location.Equals(equalLocation));
Assert.IsFalse(location.Equals(unEqualLocation));
}

private static ImportLocation CreateSampleToken() => new ImportLocation("yo", 30);
}
}
2 changes: 1 addition & 1 deletion IonDotnet.Tests/Internals/ReaderLocalTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void assertTable(ISymbolTable tab, params (string sym, int id)[] syms)
{
var symtok = tab.Find(sym.sym);
Assert.AreEqual(sym, sym, symtok.Text);
Assert.AreEqual(sym.id, symtok.Sid);
Assert.AreEqual(SymbolToken.UnknownSid, symtok.Sid);
var symText = tab.FindKnownSymbol(sym.id);
Assert.AreEqual(sym.sym, symText);
var sid = tab.FindSymbolId(sym.sym);
Expand Down
2 changes: 1 addition & 1 deletion IonDotnet.Tests/Internals/SharedSymbolTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void InternKnownText_KeepEntry(string text)

//make sure that no extra allocation is made
Assert.AreSame(text, symtok.Text);
Assert.AreEqual(1, symtok.Sid);
Assert.AreEqual(SymbolToken.UnknownSid, symtok.Sid);
}

[TestMethod]
Expand Down
41 changes: 41 additions & 0 deletions IonDotnet.Tests/Internals/SymbolTokenTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,46 @@ public void Init_SidAndTextUnknown()
Assert.AreEqual(token, SymbolToken.None);
}

[TestMethod]
[DataRow("text1", 123, "text1", 123)]
[DataRow("text2", 456, "text2", 456)]
public void Bool_EqualsOperator(string text1, int sid1, string text2, int sid2)
{
var token1 = new SymbolToken(text1, sid1);
var token2 = new SymbolToken(text2, sid2);
Assert.IsTrue(token1 == token2);
}

[TestMethod]
[DataRow("text1", 123, "text1", 456)]
[DataRow("text2", 456, "text3", 456)]
public void Bool_NotEqualsOperator(string text1, int sid1, string text2, int sid2)
{
var token1 = new SymbolToken(text1, sid1);
var token2 = new SymbolToken(text2, sid2);
Assert.IsTrue(token1 != token2);
}

[TestMethod]
public void EqualsMethod()
{
var token = CreateSampleToken();
var equalToken = new SymbolToken("yo", 30);
var unEqualToken = new SymbolToken("yo", 31);
Assert.IsTrue(token.Equals(equalToken));
Assert.IsFalse(token.Equals(unEqualToken));
}

[TestMethod]
public void IsEquivalentTo()
{
var token = CreateSampleTokenWithImportLocation();
var equalToken = new SymbolToken("yo", 30, new ImportLocation("hey", 40));
var unEqualToken = new SymbolToken("oy", 30, new ImportLocation("hey", 41));
Assert.IsTrue(token.IsEquivalentTo(equalToken));
Assert.IsFalse(token.IsEquivalentTo(unEqualToken));
}

[TestMethod]
[DataRow(0)]
[DataRow(1)]
Expand Down Expand Up @@ -58,5 +98,6 @@ public void ArrayResize_RemainderSetToDefault(int oldLength, int newLength)
}

private static SymbolToken CreateSampleToken() => new SymbolToken("yo", 30);
private static SymbolToken CreateSampleTokenWithImportLocation() => new SymbolToken("yo", 30, new ImportLocation("hey", 40));
}
}
49 changes: 49 additions & 0 deletions IonDotnet/ImportLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace IonDotnet
{
public readonly struct ImportLocation
{

/// <summary>
/// The default ImportName, which is unknown
/// </summary>
public const string UnknownImportName = default;

/// <summary>
/// The default value, corresponds to not_found/unknown
/// </summary>
public static readonly ImportLocation None = default;

/// <summary>
/// The import name of this import location.
/// </summary>
public readonly string ImportName;

/// <summary>
/// The ID of this import location.
/// </summary>
public readonly int Sid;

/// <summary>
/// Create a new ImportLocation struct.
/// </summary>
/// <param name="importName">ImportName</param>
/// <param name="sid">Sid</param>
public ImportLocation(string importName, int sid)
{
ImportName = importName;
Sid = sid;
}

public override string ToString() => $"ImportLocation::{{importName:{ImportName}, id:{Sid}}}";

public static bool operator ==(ImportLocation x, ImportLocation y) => x.ImportName == y.ImportName && x.Sid == y.Sid;

public static bool operator !=(ImportLocation x, ImportLocation y) => !(x == y);

public override bool Equals(object that) => that is ImportLocation token && Equals(token);
tgregg marked this conversation as resolved.
Show resolved Hide resolved

public bool Equals(ImportLocation other) => this == other;

public override int GetHashCode() => ImportName?.GetHashCode() ?? Sid;
}
}
4 changes: 2 additions & 2 deletions IonDotnet/Internals/Binary/ManagedBinaryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,10 @@ public override SymbolToken Find(string text)
if (text == null) throw new ArgumentNullException(nameof(text));

var found = _writer._importContext.TryGetValue(text, out var sid);
if (found) return new SymbolToken(text, sid);
if (found) return new SymbolToken(text, SymbolToken.UnknownSid);
found = _writer._locals.TryGetValue(text, out sid);

return found ? new SymbolToken(text, sid) : default;
return found ? new SymbolToken(text, SymbolToken.UnknownSid) : default;
}

public override string FindKnownSymbol(int sid)
Expand Down
6 changes: 2 additions & 4 deletions IonDotnet/Internals/ReaderLocalTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,17 @@ internal void Refresh()

public SymbolToken Find(string text)
{
var offset = 0;
foreach (var import in Imports)
{
var t = import.Find(text);
if (t != default)
return new SymbolToken(t.Text, offset + t.Sid);
offset += import.MaxId;
return new SymbolToken(t.Text, SymbolToken.UnknownSid);
}

for (var i = 0; i < _ownSymbols.Count; i++)
{
if (_ownSymbols[i] == text)
return new SymbolToken(text, i + 1 + _importedMaxId);
return new SymbolToken(text, SymbolToken.UnknownSid);
}

return default;
Expand Down
2 changes: 1 addition & 1 deletion IonDotnet/Internals/SharedSymbolTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public SymbolToken Find(string text)
return default;

var internedText = _symbolNames[sid - 1];
return new SymbolToken(internedText, sid);
return new SymbolToken(internedText, SymbolToken.UnknownSid);
}

public int FindSymbolId(string name)
Expand Down
10 changes: 5 additions & 5 deletions IonDotnet/Internals/Text/RawTextReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ private SymbolToken ParseSymbolToken(StringBuilder sb, int token)
break;
}

return new SymbolToken(text, sid);
return new SymbolToken(text, sid, new ImportLocation(GetSymbolTable().Name, sid));
}

private void FinishValue()
Expand Down Expand Up @@ -696,16 +696,16 @@ public IEnumerable<SymbolToken> GetTypeAnnotations()

foreach (var a in _annotations)
{
if (a.Text is null && a.Sid != 0)
if (a.Text is null && a.ImportLocation != default)
{
var symtab = GetSymbolTable();
if (a.Sid < -1 || a.Sid > symtab.MaxId)
if (a.ImportLocation.Sid < -1 || a.ImportLocation.Sid > symtab.MaxId)
{
throw new UnknownSymbolException(a.Sid);
}

var text = symtab.FindKnownSymbol(a.Sid);
yield return new SymbolToken(text, a.Sid);
var text = symtab.FindKnownSymbol(a.ImportLocation.Sid);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last thing, and then this is good to go:
Line 699 should be if (a.Text is null && a.ImportLocation != null) since we're relying on ImportLocation now and not local SID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean if (a.Text is null && a.ImportLocation != default)? Or is null what we are checking for in this instance?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to know if a.ImportLocation is specified. If a.ImportLocation != default is the correct way to do that, then yes that's what I mean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

yield return new SymbolToken(text, a.Sid, a.ImportLocation);
}
else
{
Expand Down
35 changes: 21 additions & 14 deletions IonDotnet/SymbolToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,28 @@ namespace IonDotnet

private readonly int _sid;

/// <summary>
/// The text of this symbol.
/// </summary>
public readonly string Text;

/// <summary>
/// The ID of this symbol token.
/// </summary>
public int Sid => _sid - 1;

/// <summary>
/// The import location of this symbol token.
/// </summary>
public readonly ImportLocation ImportLocation;

/// <summary>
/// Create a new symbol token.
/// </summary>
/// <param name="text">Text</param>
/// <param name="sid">Sid</param>
public SymbolToken(string text, int sid)
/// <param name="importLocation">ImportLocation</param>
public SymbolToken(string text, int sid, ImportLocation importLocation = default)
{
/**
* Note: due to the fact that C# structs are initialized 'blank' (all fields 0), and we want the default
Expand All @@ -41,22 +57,13 @@ public SymbolToken(string text, int sid)

Text = text;
_sid = sid + 1;
ImportLocation = importLocation;
}

/// <summary>
/// The text of this symbol.
/// </summary>
public readonly string Text;

/// <summary>
/// The ID of this symbol token.
/// </summary>
public int Sid => _sid - 1;

//Override everything to avoid boxing allocation
public override string ToString() => $"SymbolToken::{{text:{Text}, id:{Sid}}}";
public override string ToString() => $"SymbolToken::{{text:{Text}, id:{Sid}, importLocation:{ImportLocation.ToString()}}}";

public static bool operator ==(SymbolToken x, SymbolToken y) => x.Text == y.Text && x._sid == y._sid;
public static bool operator ==(SymbolToken x, SymbolToken y) => x.Text == y.Text && x.Sid == y.Sid && x.ImportLocation == y.ImportLocation;

public static bool operator !=(SymbolToken x, SymbolToken y) => !(x == y);

Expand All @@ -73,7 +80,7 @@ public bool IsEquivalentTo(SymbolToken other)
if (other.Text != null)
return false;

return other.Sid == Sid;
return other.ImportLocation == ImportLocation;
}
}
}
9 changes: 6 additions & 3 deletions IonDotnet/Tree/IonSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ namespace IonDotnet.Tree
public sealed class IonSymbol : IonText
{
private int _sid;
private ImportLocation _importLocation;

public IonSymbol(string text, int sid = SymbolToken.UnknownSid) : this(new SymbolToken(text, sid))
public IonSymbol(string text, int sid = SymbolToken.UnknownSid, ImportLocation importLocation = default) : this(new SymbolToken(text, sid, importLocation))
{
}

public IonSymbol(SymbolToken symbolToken) : base(symbolToken.Text, symbolToken == default)
{
_sid = symbolToken.Sid;
_importLocation = symbolToken.ImportLocation;
}

private IonSymbol(bool isNull) : base(null, isNull)
Expand All @@ -28,7 +30,7 @@ public override bool IsEquivalentTo(IonValue other)
{
if (!base.IsEquivalentTo(other))
return false;

if (!(other is IonSymbol oSymbol))
return false;

Expand Down Expand Up @@ -63,11 +65,12 @@ public override string StringValue

public SymbolToken SymbolValue
{
get => new SymbolToken(StringVal, _sid);
get => new SymbolToken(StringVal, _sid, _importLocation);
set
{
StringValue = value.Text;
_sid = value.Sid;
_importLocation = value.ImportLocation;
}
}
}
Expand Down