Skip to content

Commit

Permalink
Merge pull request #143 from marcin-golebiowski/master
Browse files Browse the repository at this point in the history
Include column information in tokens and netlist model, improve exceptions
  • Loading branch information
marcin-golebiowski authored Dec 19, 2019
2 parents 3c7dc4e + c62b446 commit ec27e9d
Show file tree
Hide file tree
Showing 19 changed files with 354 additions and 157 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;

namespace SpiceSharpParser.Lexers
{
Expand Down
30 changes: 30 additions & 0 deletions src/SpiceSharpParser/Common/ILocationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace SpiceSharpParser.Common
{
public interface ILocationProvider
{
/// <summary>
/// Gets or sets token line number.
/// </summary>
int LineNumber { get; }

/// <summary>
/// Gets or sets start column index.
/// </summary>
int StartColumnIndex { get; }

/// <summary>
/// Gets or sets end column index.
/// </summary>
int EndColumnIndex { get; }

/// <summary>
/// Gets token file name.
/// </summary>
string FileName { get; }
}

}
15 changes: 9 additions & 6 deletions src/SpiceSharpParser/Common/SpiceSharpParserException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@ public SpiceSharpParserException(string message)
}

public SpiceSharpParserException(string message, SpiceLineInfo lineInfo)
: base(
lineInfo != null ?
lineInfo.FileName != null
? $"{message} (at line {lineInfo?.LineNumber} from file {lineInfo.FileName})"
: $"{message} (at line {lineInfo?.LineNumber})" : $"{message}")
: base(CreateExceptionMessage(message, lineInfo))
{
LineInfo = lineInfo;
}
private static string CreateExceptionMessage(string message, SpiceLineInfo lineInfo)
{
return lineInfo != null ?
lineInfo.FileName != null
? $"{message} (at line {lineInfo?.LineNumber}, start column = {lineInfo?.StartColumnIndex}, end column = {lineInfo?.EndColumnIndex} from file {lineInfo.FileName})"
: $"{message} (at line {lineInfo?.LineNumber}, start column = {lineInfo?.StartColumnIndex}, end column = {lineInfo?.EndColumnIndex})" : $"{message}";
}

public SpiceSharpParserException(string message, Exception innerException)
: base(message, innerException)
{
}

public SpiceSharpParserException(string message, Exception innerException, SpiceLineInfo lineInfo)
: base(message, innerException)
: base(CreateExceptionMessage(message, lineInfo), innerException)
{
LineInfo = lineInfo;
}
Expand Down
25 changes: 11 additions & 14 deletions src/SpiceSharpParser/Lexers/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public class Lexer<TLexerState>
/// Initializes a new instance of the <see cref="Lexer{TLexerState}"/> class.
/// </summary>
/// <param name="grammar">Lexer grammar.</param>
/// <param name="options">Lexer options.</param>
public Lexer(LexerGrammar<TLexerState> grammar)
{
Grammar = grammar ?? throw new ArgumentNullException(nameof(grammar));
Expand All @@ -40,7 +39,7 @@ public IEnumerable<Token> GetTokens(string text, TLexerState state = null)
}

int currentTokenIndex = 0;
var lineProvider = new LexerLineNumberProvider(text);
var lineProvider = new LexerLineInfoProvider(text);

if (state != null)
{
Expand All @@ -52,16 +51,9 @@ public IEnumerable<Token> GetTokens(string text, TLexerState state = null)
if (state != null)
{
var currentLineIndex = lineProvider.GetLineForIndex(currentTokenIndex);
if (state.LineNumber != currentLineIndex)
{
state.NewLine = true;
}
else
{
state.NewLine = false;
}

state.NewLine = state.LineNumber != currentLineIndex;
state.LineNumber = currentLineIndex;
state.StartColumnIndex = lineProvider.GetColumnForIndex(currentTokenIndex);
}

if (FindBestTokenRule(text, currentTokenIndex, state, out var bestTokenRule, out var bestMatch))
Expand All @@ -74,7 +66,12 @@ public IEnumerable<Token> GetTokens(string text, TLexerState state = null)
state.PreviousReturnedTokenType = bestTokenRule.TokenType;
}

yield return new Token(bestTokenRule.TokenType, bestMatch.Value, state?.LineNumber ?? 0, null);
yield return new Token(
bestTokenRule.TokenType,
bestMatch.Value,
state?.LineNumber ?? 0,
state?.StartColumnIndex ?? 0,
null);
}

currentTokenIndex += bestMatch.Length;
Expand All @@ -90,7 +87,7 @@ public IEnumerable<Token> GetTokens(string text, TLexerState state = null)
{
var dynamicResult = dynamicRule.Action(textForDynamicRules);

yield return new Token(dynamicRule.TokenType, dynamicResult.Item1, state?.LineNumber ?? 0, null);
yield return new Token(dynamicRule.TokenType, dynamicResult.Item1, state?.LineNumber ?? 0, state?.StartColumnIndex ?? 0, null);

currentTokenIndex += dynamicResult.Item2;
matched = true;
Expand All @@ -105,7 +102,7 @@ public IEnumerable<Token> GetTokens(string text, TLexerState state = null)
}

// yield EOF token
yield return new Token(-1, "EOF", state?.LineNumber ?? 0, null);
yield return new Token(-1, "EOF", state?.LineNumber ?? 0, state?.StartColumnIndex ??0, null);
}

/// <summary>
Expand Down
134 changes: 134 additions & 0 deletions src/SpiceSharpParser/Lexers/LexerLineInfoProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using System.Collections.Generic;

namespace SpiceSharpParser.Lexers
{
public class LexerLineInfoProvider
{
private readonly string _text;
private readonly List<LexerLineRange> _ranges = new List<LexerLineRange>();

public LexerLineInfoProvider(string text)
{
_text = text;

Init();
}

public int GetLineForIndex(int textIndex)
{
// binary search over line ranges
int start = 0;
int end = _ranges.Count - 1;

while (start <= end)
{
int middle = (end + start) / 2;

if (_ranges[middle].From <= textIndex && textIndex <= _ranges[middle].To)
{
return _ranges[middle].LineNumber;
}
else if (_ranges[middle].From > textIndex)
{
end = middle - 1;
}
else if (_ranges[middle].To < textIndex)
{
start = middle + 1;
}
else
{
return -1;
}
}

return -1;
}

public int GetColumnForIndex(int textIndex)
{
// binary search over line ranges
int start = 0;
int end = _ranges.Count - 1;

while (start <= end)
{
int middle = (end + start) / 2;

if (_ranges[middle].From <= textIndex && textIndex <= _ranges[middle].To)
{
return textIndex - _ranges[middle].From;
}
else if (_ranges[middle].From > textIndex)
{
end = middle - 1;
}
else if (_ranges[middle].To < textIndex)
{
start = middle + 1;
}
else
{
return -1;
}
}

return -1;
}

private void Init()
{
int currentIndex = 0;

var newRange = new LexerLineRange { From = 0, LineNumber = 1 };
int currentLineNumber = 1;

while (currentIndex < _text.Length)
{
if (_text[currentIndex] == '\r')
{
if ((_text.Length > currentIndex + 1) && _text[currentIndex + 1] == '\n')
{
newRange.To = currentIndex + 1;
newRange.LineNumber = currentLineNumber;
_ranges.Add(newRange);

currentLineNumber++;
currentIndex += 2;

newRange = new LexerLineRange { From = currentIndex, LineNumber = currentLineNumber };
}
else
{
newRange.To = currentIndex;
newRange.LineNumber = currentLineNumber;
_ranges.Add(newRange);

currentLineNumber++;
currentIndex++;

newRange = new LexerLineRange { From = currentIndex, LineNumber = currentLineNumber };
}
}
else if (_text[currentIndex] == '\n')
{
newRange.To = currentIndex;
newRange.LineNumber = currentLineNumber;
_ranges.Add(newRange);

currentLineNumber++;
currentIndex++;

newRange = new LexerLineRange { From = currentIndex, LineNumber = currentLineNumber };
}
else
{
currentIndex++;
}
}

newRange.To = _text.Length - 1;
_ranges.Add(newRange);
}
}
}
7 changes: 6 additions & 1 deletion src/SpiceSharpParser/Lexers/LexerState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ public class LexerState
/// <summary>
/// Gets or sets the current line number.
/// </summary>
public int LineNumber { get; set; } = 1;
public int LineNumber { get; set; } = 0;

/// <summary>
/// Gets or sets the start column index.
/// </summary>
public int StartColumnIndex { get; set; }

/// <summary>
/// Gets or sets a value indicating lexer is lexing new line.
Expand Down
2 changes: 1 addition & 1 deletion src/SpiceSharpParser/Lexers/Netlist/Spice/SpiceLexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public IEnumerable<SpiceToken> GetTokens(string netlistText)

foreach (var token in lexer.GetTokens(netlistText, state))
{
yield return new SpiceToken((SpiceTokenType)token.Type, token.Lexem, state.LineNumber);
yield return new SpiceToken((SpiceTokenType)token.Type, token.Lexem, state.LineNumber, state.StartColumnIndex,null);
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/SpiceSharpParser/Lexers/Netlist/Spice/SpiceToken.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using SpiceSharpParser.Models.Netlist.Spice;

namespace SpiceSharpParser.Lexers.Netlist.Spice
namespace SpiceSharpParser.Lexers.Netlist.Spice
{
/// <summary>
/// A token from SPICE netlist.
Expand All @@ -10,8 +8,8 @@ public class SpiceToken : Token
/// <summary>
/// Initializes a new instance of the <see cref="SpiceToken"/> class.
/// </summary>
public SpiceToken(SpiceTokenType tokenType, string lexem, int lineNumber = 0, string fileName = null)
: base((int)tokenType, lexem, lineNumber, fileName)
public SpiceToken(SpiceTokenType tokenType, string lexem, int lineNumber = 0, int startColumnIndex = 0, string fileName = null)
: base((int)tokenType, lexem, lineNumber, startColumnIndex, fileName)
{
SpiceTokenType = tokenType;
}
Expand Down
23 changes: 18 additions & 5 deletions src/SpiceSharpParser/Lexers/Token.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
namespace SpiceSharpParser.Lexers
using SpiceSharpParser.Common;

namespace SpiceSharpParser.Lexers
{
/// <summary>
/// A token produces by <see cref="Lexer{TLexerState}"/>.
/// </summary>
public class Token
public class Token : ILocationProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="Token"/> class.
/// </summary>
public Token(int tokenType, string lexem, int lineNumber, string fileName)
public Token(int tokenType, string lexem, int lineNumber, int startColumnIndex, string fileName)
{
Type = tokenType;
Lexem = lexem;
LineNumber = lineNumber;
StartColumnIndex = startColumnIndex;
FileName = fileName;
}

Expand All @@ -22,12 +25,22 @@ public Token(int tokenType, string lexem, int lineNumber, string fileName)
public int Type { get; }

/// <summary>
/// Gets token line number.
/// Gets or sets token line number.
/// </summary>
public int LineNumber { get; set; }

/// <summary>
/// Gets token file name.
/// Gets or sets start column index.
/// </summary>
public int StartColumnIndex { get; set; }

/// <summary>
/// Gets end column index.
/// </summary>
public int EndColumnIndex => StartColumnIndex + (Lexem?.Length ?? 0);

/// <summary>
/// Gets or sets token file name.
/// </summary>
public string FileName { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public double EvaluateDouble(string expression)
{
return ParsingContext.Evaluate(expression);
}
catch (SpiceSharpParserException)
{
throw;
}
catch (Exception ex)
{
throw new SpiceSharpParserException($"Exception during evaluation of expression: {expression}", ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,19 @@ protected SpiceSharp.Components.Component GenerateRes(string name, ParameterColl
{
if (parameter is AssignmentParameter ap)
{
context.SetParameter(res, ap.Name, ap.Value);
try
{
context.SetParameter(res, ap.Name, ap.Value);
}
catch (Exception e)
{
throw new ReadingException($"Can't set parameter for resistor: '{parameter.Image}'", e, parameter.LineInfo);
}

}
else
{
throw new ReadingException("Invalid parameter for resistor: " + parameter.Image);
throw new ReadingException($"Invalid parameter for resistor: '{parameter.Image}'", parameter.LineInfo);
}
}
}
Expand Down
Loading

0 comments on commit ec27e9d

Please sign in to comment.