Faster number lexing, better handling of exceptions in C# code
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
a9dbb2c1ed
commit
c4c3f65074
|
@ -159,8 +159,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
Exception exception = e;
|
Exception exception = e;
|
||||||
if (e.InnerException != null) exception = e.InnerException;
|
if (e.InnerException != null) exception = e.InnerException;
|
||||||
throw new EvaluationException(state.Script.FileName,
|
throw new EvaluationException(state.Script.FileName, exception, span, state.Stacktrace);
|
||||||
"An Exception occured while executing a C# function:\n" + exception, span, state.Stacktrace);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,15 @@ namespace Upsilon.Exceptions
|
||||||
Span = span;
|
Span = span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EvaluationException(string fileName, Exception inner, TextSpan span, Stacktrace stacktrace = null)
|
||||||
|
: base("An exception occured in called C# code. See the inner exception for more details.", inner)
|
||||||
|
{
|
||||||
|
_stacktrace = stacktrace;
|
||||||
|
FileName = fileName;
|
||||||
|
ErrorMessage = Message;
|
||||||
|
Span = span;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var err = new StringBuilder($"[{FileName}] ({Span.StartLine},{Span.StartPosition}) {ErrorMessage}");
|
var err = new StringBuilder($"[{FileName}] ({Span.StartLine},{Span.StartPosition}) {ErrorMessage}");
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Upsilon.Parser
|
||||||
public class IdentifierToken : SyntaxToken
|
public class IdentifierToken : SyntaxToken
|
||||||
{
|
{
|
||||||
public IdentifierToken(string name, TextSpan position)
|
public IdentifierToken(string name, TextSpan position)
|
||||||
: base(SyntaxKind.Identifier, position, name, null)
|
: base(SyntaxKind.Identifier, position, null)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,53 +88,53 @@ namespace Upsilon.Parser
|
||||||
switch (Current)
|
switch (Current)
|
||||||
{
|
{
|
||||||
case '\0':
|
case '\0':
|
||||||
return new SyntaxToken(SyntaxKind.EndOfFile, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "\0", null);
|
return new SyntaxToken(SyntaxKind.EndOfFile, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case ' ': case '\t': case '\r':
|
case ' ': case '\t': case '\r':
|
||||||
return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), Current.ToString(), null);
|
return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '\n':
|
case '\n':
|
||||||
{
|
{
|
||||||
_linePosition++;
|
_linePosition++;
|
||||||
var pos = _position;
|
var pos = _position;
|
||||||
_position = -1;
|
_position = -1;
|
||||||
return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, pos, _linePosition, pos + 1), "\n", null);
|
return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, pos, _linePosition, pos + 1), null);
|
||||||
}
|
}
|
||||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||||
return LexNumber();
|
return LexNumber();
|
||||||
case '+':
|
case '+':
|
||||||
return new SyntaxToken(SyntaxKind.Plus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "+", null);
|
return new SyntaxToken(SyntaxKind.Plus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '-':
|
case '-':
|
||||||
if (Next == '-')
|
if (Next == '-')
|
||||||
{
|
{
|
||||||
_position++;
|
_position++;
|
||||||
return LexComments();
|
return LexComments();
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Minus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "-", null);
|
return new SyntaxToken(SyntaxKind.Minus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '*':
|
case '*':
|
||||||
return new SyntaxToken(SyntaxKind.Star, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "*", null);
|
return new SyntaxToken(SyntaxKind.Star, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '/':
|
case '/':
|
||||||
return new SyntaxToken(SyntaxKind.Slash, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "/", null);
|
return new SyntaxToken(SyntaxKind.Slash, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '(':
|
case '(':
|
||||||
return new SyntaxToken(SyntaxKind.OpenParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "(", null);
|
return new SyntaxToken(SyntaxKind.OpenParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case ')':
|
case ')':
|
||||||
return new SyntaxToken(SyntaxKind.CloseParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ")", null);
|
return new SyntaxToken(SyntaxKind.CloseParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '{':
|
case '{':
|
||||||
return new SyntaxToken(SyntaxKind.OpenBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "{", null);
|
return new SyntaxToken(SyntaxKind.OpenBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '}':
|
case '}':
|
||||||
return new SyntaxToken(SyntaxKind.CloseBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "}", null);
|
return new SyntaxToken(SyntaxKind.CloseBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '[':
|
case '[':
|
||||||
return new SyntaxToken(SyntaxKind.OpenBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "[", null);
|
return new SyntaxToken(SyntaxKind.OpenBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case ']':
|
case ']':
|
||||||
return new SyntaxToken(SyntaxKind.CloseBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "]", null);
|
return new SyntaxToken(SyntaxKind.CloseBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '.':
|
case '.':
|
||||||
return new SyntaxToken(SyntaxKind.FullStop, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ".", null);
|
return new SyntaxToken(SyntaxKind.FullStop, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case ',':
|
case ',':
|
||||||
return new SyntaxToken(SyntaxKind.Comma, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ",", null);
|
return new SyntaxToken(SyntaxKind.Comma, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '#':
|
case '#':
|
||||||
return new SyntaxToken(SyntaxKind.PoundSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "#", null);
|
return new SyntaxToken(SyntaxKind.PoundSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '%':
|
case '%':
|
||||||
return new SyntaxToken(SyntaxKind.PercentSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "%", null);
|
return new SyntaxToken(SyntaxKind.PercentSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '^':
|
case '^':
|
||||||
return new SyntaxToken(SyntaxKind.RoofSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "^", null);
|
return new SyntaxToken(SyntaxKind.RoofSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '"':
|
case '"':
|
||||||
case '\'':
|
case '\'':
|
||||||
return LexString(Current);
|
return LexString(Current);
|
||||||
|
@ -142,35 +142,35 @@ namespace Upsilon.Parser
|
||||||
if (Next == '=')
|
if (Next == '=')
|
||||||
{
|
{
|
||||||
_position++;
|
_position++;
|
||||||
return new SyntaxToken(SyntaxKind.EqualsEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "==", null);
|
return new SyntaxToken(SyntaxKind.EqualsEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Equals, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "=", null);
|
return new SyntaxToken(SyntaxKind.Equals, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '~':
|
case '~':
|
||||||
if (Next == '=')
|
if (Next == '=')
|
||||||
{
|
{
|
||||||
_position++;
|
_position++;
|
||||||
return new SyntaxToken(SyntaxKind.TildeEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "~=", null);
|
return new SyntaxToken(SyntaxKind.TildeEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Tilde, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "~", null);
|
return new SyntaxToken(SyntaxKind.Tilde, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '<':
|
case '<':
|
||||||
if (Next == '=')
|
if (Next == '=')
|
||||||
{
|
{
|
||||||
_position++;
|
_position++;
|
||||||
return new SyntaxToken(SyntaxKind.LessEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "<=", null);
|
return new SyntaxToken(SyntaxKind.LessEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Less, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "<", null);
|
return new SyntaxToken(SyntaxKind.Less, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
case '>':
|
case '>':
|
||||||
if (Next == '=')
|
if (Next == '=')
|
||||||
{
|
{
|
||||||
_position++;
|
_position++;
|
||||||
return new SyntaxToken(SyntaxKind.GreaterEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), ">=", null);
|
return new SyntaxToken(SyntaxKind.GreaterEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(SyntaxKind.Greater, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ">", null);
|
return new SyntaxToken(SyntaxKind.Greater, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
default:
|
default:
|
||||||
if (char.IsLetter(Current) || Current == '_')
|
if (char.IsLetter(Current) || Current == '_')
|
||||||
return LexIdentifierOrKeyword();
|
return LexIdentifierOrKeyword();
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Identifier);
|
_diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Identifier);
|
||||||
return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "", null);
|
return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,30 +178,65 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
var start = _position;
|
var start = _position;
|
||||||
var hasDecimalPoint = false;
|
var hasDecimalPoint = false;
|
||||||
var numStr = new StringBuilder();
|
long num = ParseChar(Current);
|
||||||
numStr.Append(Current);
|
double floatNum = 0f;
|
||||||
while (char.IsDigit(Next) || Next == '.' || Next == '_')
|
var decimalPlace = 0;
|
||||||
|
char c = Next;
|
||||||
|
while (char.IsDigit(c) || c == '.' || c == '_')
|
||||||
{
|
{
|
||||||
if (Next == '.')
|
if (c == '.')
|
||||||
{
|
{
|
||||||
if (hasDecimalPoint)
|
if (hasDecimalPoint)
|
||||||
{
|
{
|
||||||
_diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Number);
|
_diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Number);
|
||||||
return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "", null);
|
return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
hasDecimalPoint = true;
|
hasDecimalPoint = true;
|
||||||
|
floatNum = Convert.ToDouble(num);
|
||||||
|
decimalPlace++;
|
||||||
|
}
|
||||||
|
else if (c != '_')
|
||||||
|
{
|
||||||
|
var parsed = ParseChar(c);
|
||||||
|
if (hasDecimalPoint)
|
||||||
|
{
|
||||||
|
floatNum += parsed / Math.Pow(10, decimalPlace);
|
||||||
|
decimalPlace++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num *= 10;
|
||||||
|
num += parsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Next != '_')
|
|
||||||
numStr.Append(Next);
|
|
||||||
_position++;
|
_position++;
|
||||||
|
c = Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
object o;
|
object o;
|
||||||
if (hasDecimalPoint)
|
if (hasDecimalPoint)
|
||||||
o = double.Parse(numStr.ToString());
|
o = floatNum;
|
||||||
else
|
else
|
||||||
o = long.Parse(numStr.ToString());
|
o = num;
|
||||||
return new SyntaxToken(SyntaxKind.Number, new TextSpan(_linePosition, start, _linePosition, _position + 1), numStr.ToString(), o);
|
return new SyntaxToken(SyntaxKind.Number, new TextSpan(_linePosition, start, _linePosition, _position + 1), o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte ParseChar(char c)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '0': return 0;
|
||||||
|
case '1': return 1;
|
||||||
|
case '2': return 2;
|
||||||
|
case '3': return 3;
|
||||||
|
case '4': return 4;
|
||||||
|
case '5': return 5;
|
||||||
|
case '6': return 6;
|
||||||
|
case '7': return 7;
|
||||||
|
case '8': return 8;
|
||||||
|
case '9': return 9;
|
||||||
|
default: throw new ArgumentException($"Expected digit, got {c}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SyntaxToken LexString(char current)
|
private SyntaxToken LexString(char current)
|
||||||
|
@ -230,8 +265,7 @@ namespace Upsilon.Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = sb.ToString();
|
var res = sb.ToString();
|
||||||
return new SyntaxToken(SyntaxKind.String, new TextSpan(_linePosition, start, _linePosition, _position + 1),
|
return new SyntaxToken(SyntaxKind.String, new TextSpan(_linePosition, start, _linePosition, _position + 1), res);
|
||||||
$"\"{res}\"", res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SyntaxToken LexIdentifierOrKeyword()
|
private SyntaxToken LexIdentifierOrKeyword()
|
||||||
|
@ -257,7 +291,7 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
return new ReturnSyntaxToken(new TextSpan(_linePosition, start, _linePosition, _position + 1), Next == Environment.NewLine[0]);
|
return new ReturnSyntaxToken(new TextSpan(_linePosition, start, _linePosition, _position + 1), Next == Environment.NewLine[0]);
|
||||||
}
|
}
|
||||||
return new SyntaxToken(kind, new TextSpan(_linePosition, start, _linePosition, _position + 1), str, null);
|
return new SyntaxToken(kind, new TextSpan(_linePosition, start, _linePosition, _position + 1), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SyntaxToken LexComments()
|
private SyntaxToken LexComments()
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Upsilon.Parser
|
||||||
private SyntaxToken Get(int offset)
|
private SyntaxToken Get(int offset)
|
||||||
{
|
{
|
||||||
if (_position + offset >= _tokens.Length)
|
if (_position + offset >= _tokens.Length)
|
||||||
return new SyntaxToken(SyntaxKind.EndOfFile, _tokens.Last().Span, "\0", null);
|
return new SyntaxToken(SyntaxKind.EndOfFile, _tokens.Last().Span, null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return _tokens[_position + offset];
|
return _tokens[_position + offset];
|
||||||
|
@ -49,7 +49,7 @@ namespace Upsilon.Parser
|
||||||
return NextToken();
|
return NextToken();
|
||||||
|
|
||||||
_diagnostics.LogBadCharacter(Current.Span, kind, Current.Kind);
|
_diagnostics.LogBadCharacter(Current.Span, kind, Current.Kind);
|
||||||
return new SyntaxToken(kind, Current.Span, "", null);
|
return new SyntaxToken(kind, Current.Span, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StatementSyntax ParseScriptSyntax()
|
private StatementSyntax ParseScriptSyntax()
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Upsilon.Parser
|
||||||
{
|
{
|
||||||
public class SyntaxToken : SyntaxNode
|
public class SyntaxToken : SyntaxNode
|
||||||
{
|
{
|
||||||
public SyntaxToken(SyntaxKind kind, TextSpan position, string text, object value)
|
public SyntaxToken(SyntaxKind kind, TextSpan position, object value)
|
||||||
{
|
{
|
||||||
Kind = kind;
|
Kind = kind;
|
||||||
Span = position;
|
Span = position;
|
||||||
|
@ -34,7 +34,7 @@ namespace Upsilon.Parser
|
||||||
public bool FollowedByLineBreak { get; }
|
public bool FollowedByLineBreak { get; }
|
||||||
|
|
||||||
public ReturnSyntaxToken(TextSpan position, bool followedByLineBreak)
|
public ReturnSyntaxToken(TextSpan position, bool followedByLineBreak)
|
||||||
: base(SyntaxKind.ReturnKeyword, position, "return", null)
|
: base(SyntaxKind.ReturnKeyword, position, null)
|
||||||
{
|
{
|
||||||
FollowedByLineBreak = followedByLineBreak;
|
FollowedByLineBreak = followedByLineBreak;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Upsilon;
|
using Upsilon;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace UpsilonTests.StandardLibraryTests
|
namespace UpsilonTests.StandardLibraryTests
|
||||||
|
@ -14,14 +15,14 @@ namespace UpsilonTests.StandardLibraryTests
|
||||||
public void AssertTest()
|
public void AssertTest()
|
||||||
{
|
{
|
||||||
Executor.EvaluateScript("assert(true)", Options);
|
Executor.EvaluateScript("assert(true)", Options);
|
||||||
Assert.Throws<Exception>(() => Executor.EvaluateScript("assert(false)", Options));
|
Assert.Throws<EvaluationException>(() => Executor.EvaluateScript("assert(false)", Options));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Error()
|
public void Error()
|
||||||
{
|
{
|
||||||
var e = Assert.Throws<Exception>(() => Executor.EvaluateScript(@"error(""test_error"")", Options));
|
var e = Assert.Throws<EvaluationException>(() => Executor.EvaluateScript(@"error(""test_error"")", Options));
|
||||||
Assert.Equal("test_error", e.Message);
|
Assert.Equal("test_error", e.InnerException.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
Loading…
Reference in New Issue