Exception throwing when required, and fixes for unit tests

This commit is contained in:
Deukhoofd 2018-11-26 17:23:56 +01:00
parent 74da87d936
commit b7d01b02f1
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
14 changed files with 73 additions and 29 deletions

View File

@ -201,12 +201,6 @@ namespace Upsilon.Binder
{ {
var variableExpression =(BoundVariableExpression) expression; var variableExpression =(BoundVariableExpression) expression;
var function = (FunctionVariableSymbol)variableExpression.Variable.VariableSymbol; var function = (FunctionVariableSymbol)variableExpression.Variable.VariableSymbol;
if (function.Parameters.Length != parameters.Count)
{
_diagnostics.LogError($"Invalid number of parameters for function '{function.Name}'. " +
$"Expected '{function.Parameters.Length}', got '{parameters.Count}'", e.Span);
return new BoundLiteralExpression(new ScriptNull(), e.Span);
}
if (!function.IsBound) if (!function.IsBound)
{ {
Scope = new BoundScope(Scope); Scope = new BoundScope(Scope);

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.Exceptions;
using Upsilon.Parser; using Upsilon.Parser;
using Upsilon.Text; using Upsilon.Text;
@ -9,10 +10,12 @@ namespace Upsilon
{ {
public SourceText ScriptString { get; } public SourceText ScriptString { get; }
public readonly List<DiagnosticsMessage> Messages = new List<DiagnosticsMessage>(); public readonly List<DiagnosticsMessage> Messages = new List<DiagnosticsMessage>();
public bool ThrowsOnError { get; }
public Diagnostics(SourceText scriptString) public Diagnostics(SourceText scriptString, bool throwsOnError)
{ {
ScriptString = scriptString; ScriptString = scriptString;
ThrowsOnError = throwsOnError;
} }
public void Log(DiagnosticLevel level, string message, TextSpan location) public void Log(DiagnosticLevel level, string message, TextSpan location)
@ -22,6 +25,12 @@ namespace Upsilon
public void LogError(string message, TextSpan location) public void LogError(string message, TextSpan location)
{ {
if (ThrowsOnError)
{
var linePos = ScriptString.GetLinePosition(location.Start);
var line = ScriptString.GetLine(linePos.Line);
throw new ParseException(message, linePos.Line, linePos.Pos, line);
}
Log(DiagnosticLevel.Error, message, location); Log(DiagnosticLevel.Error, message, location);
} }

View File

@ -27,7 +27,7 @@ namespace Upsilon.Evaluator
Options = options; Options = options;
_scriptString = scriptString; _scriptString = scriptString;
ScriptString = new SourceText(scriptString); ScriptString = new SourceText(scriptString);
Diagnostics = new Diagnostics(ScriptString); Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError);
var staticBoundScope = options.OverrideStaticBoundScope ?? StaticScope.BoundScope; var staticBoundScope = options.OverrideStaticBoundScope ?? StaticScope.BoundScope;
var boundScope = BoundScope.WithReadOnlyScope(staticBoundScope); var boundScope = BoundScope.WithReadOnlyScope(staticBoundScope);
@ -38,10 +38,10 @@ namespace Upsilon.Evaluator
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope); Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope);
} }
private Script(string scriptString, Binder.Binder binder, Evaluator evaluator) private Script(string scriptString, Binder.Binder binder, Evaluator evaluator, ScriptOptions options)
{ {
ScriptString = new SourceText(scriptString); ScriptString = new SourceText(scriptString);
Diagnostics = new Diagnostics(ScriptString); Diagnostics = new Diagnostics(ScriptString, Options.ThrowExceptionOnError);
Binder = new Binder.Binder(Diagnostics, binder.Scope.Variables); Binder = new Binder.Binder(Diagnostics, binder.Scope.Variables);
Evaluator = new Evaluator( Diagnostics, evaluator.Scope.Variables); Evaluator = new Evaluator( Diagnostics, evaluator.Scope.Variables);
Scope = Evaluator.Scope; Scope = Evaluator.Scope;
@ -50,7 +50,7 @@ namespace Upsilon.Evaluator
internal static Script ContinueWith(Script previousScript, string scriptString) internal static Script ContinueWith(Script previousScript, string scriptString)
{ {
var s = new Script(scriptString, previousScript.Binder, previousScript.Evaluator); var s = new Script(scriptString, previousScript.Binder, previousScript.Evaluator, previousScript.Options);
return s; return s;
} }

View File

@ -0,0 +1,28 @@
using System;
using Upsilon.Text;
namespace Upsilon.Exceptions
{
public class ParseException : Exception
{
public string ErrorMessage { get; }
public int Line { get; }
public int Character { get; }
public string ErrorLine { get; }
public ParseException(string errorMessage, int line, int character, string errorLine)
{
ErrorMessage = errorMessage;
Line = line;
Character = character;
ErrorLine = errorLine;
}
public override string ToString()
{
return $"{ErrorMessage} at ({Line}, {Character})\n{ErrorLine}";
}
public override string Message => ToString();
}
}

View File

@ -44,13 +44,13 @@ namespace Upsilon
public static T EvaluateFunction<T>(string input, string function, object[] parameters = null, ScriptOptions options = null) public static T EvaluateFunction<T>(string input, string function, object[] parameters = null, ScriptOptions options = null)
{ {
var script = ParseInput(input, options); var script = ParseInputAndEvaluate(input, options);
return script.EvaluateFunction<T>(function, parameters); return script.EvaluateFunction<T>(function, parameters);
} }
public static object EvaluateFunction(string input, string function, object[] parameters = null, ScriptOptions options = null) public static object EvaluateFunction(string input, string function, object[] parameters = null, ScriptOptions options = null)
{ {
var script = ParseInput(input, options); var script = ParseInputAndEvaluate(input, options);
return script.EvaluateFunction(function, parameters); return script.EvaluateFunction(function, parameters);
} }
} }

View File

@ -16,7 +16,9 @@ namespace Upsilon.Parser
ThenToken = thenToken; ThenToken = thenToken;
Block = block; Block = block;
EndToken = endToken; EndToken = endToken;
Span = new TextSpan(IfToken.Span.Start, EndToken.Span.End - IfToken.Span.Start); var end = Block.Span.End;
if (EndToken != null) end = EndToken.Span.End;
Span = new TextSpan(IfToken.Span.Start, end - IfToken.Span.Start);
} }
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,
@ -27,7 +29,7 @@ namespace Upsilon.Parser
ThenToken = thenToken; ThenToken = thenToken;
Block = block; Block = block;
ElseStatement = elseStatement; ElseStatement = elseStatement;
Span = new TextSpan(IfToken.Span.Start, EndToken.Span.End - IfToken.Span.Start); Span = new TextSpan(IfToken.Span.Start, ElseStatement.Span.End - IfToken.Span.Start);
} }
public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken,

View File

@ -85,6 +85,12 @@ namespace Upsilon.Text
return _text.Length; return _text.Length;
} }
public string GetLine(int linePosition)
{
var line = _lines[linePosition];
return GetSpan(line.Start, line.LineLength);
}
public SourceTextLine GetLineInfo(int lineIndex) public SourceTextLine GetLineInfo(int lineIndex)
{ {
return _lines[lineIndex]; return _lines[lineIndex];

View File

@ -1,5 +1,6 @@
using Upsilon; using Upsilon;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Exceptions;
using Xunit; using Xunit;
namespace UpsilonTests.GeneralTests namespace UpsilonTests.GeneralTests
@ -50,8 +51,7 @@ function testFunc (var1)
end end
testFunc(100) testFunc(100)
"; ";
var script = Executor.ParseInputAndEvaluate(input, Options); Assert.Throws<ParseException>(() => Executor.ParseInputAndEvaluate(input, Options));
Assert.True(script.HasVariable("testFunc"));
} }
[Fact] [Fact]

View File

@ -1,5 +1,6 @@
using Upsilon; using Upsilon;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Exceptions;
using Xunit; using Xunit;
namespace UpsilonTests.GeneralTests namespace UpsilonTests.GeneralTests
@ -49,7 +50,7 @@ table = {
} }
return table[""test""] return table[""test""]
"; ";
Executor.EvaluateScript<long>(input, Options); Assert.Throws<ParseException>(() => Executor.EvaluateScript<long>(input, Options));
} }
[Fact] [Fact]

View File

@ -21,7 +21,7 @@ function getValue(arr)
return arr[""here""] return arr[""here""]
end end
"; ";
var evaluated = Executor.EvaluateScript<long>(input, Options); var evaluated = Executor.EvaluateFunction<long>(input, "getValue", new[] {arr}, Options);
Assert.Equal(1683, evaluated); Assert.Equal(1683, evaluated);
} }

View File

@ -16,7 +16,7 @@ function getValue(arr)
return arr[3] return arr[3]
end end
"; ";
var evaluated = Executor.EvaluateScript<long>(input, Options); var evaluated = Executor.EvaluateFunction<long>(input, "getValue", new []{arr}, Options);
Assert.Equal(56, evaluated); Assert.Equal(56, evaluated);
} }
@ -29,7 +29,7 @@ function getValue(arr)
return arr[2] return arr[2]
end end
"; ";
var evaluated = Executor.EvaluateScript<long>(input, Options); var evaluated = Executor.EvaluateFunction<long>(input, "getValue", new []{arr}, Options);
Assert.Equal(30, evaluated); Assert.Equal(30, evaluated);
} }

View File

@ -2,6 +2,7 @@ using System;
using Upsilon; using Upsilon;
using Upsilon.BaseTypes.UserData; using Upsilon.BaseTypes.UserData;
using Upsilon.Evaluator; using Upsilon.Evaluator;
using Upsilon.Exceptions;
using Xunit; using Xunit;
// ReSharper disable UnusedMember.Local // ReSharper disable UnusedMember.Local
@ -68,7 +69,7 @@ function test(o)
o.FieldStringSet = ""Test"" o.FieldStringSet = ""Test""
end end
"; ";
var result = Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options); Executor.EvaluateFunction(input, "test", new[] {obj}, Options);
Assert.Equal("Test", obj.FieldStringSet); Assert.Equal("Test", obj.FieldStringSet);
} }
@ -81,7 +82,7 @@ function test(o)
o.testMethod() o.testMethod()
end end
"; ";
Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options); Executor.EvaluateFunction(input, "test", new[] {obj}, Options);
} }
[Fact] [Fact]
@ -106,7 +107,7 @@ function test(o)
return o._privateTestField return o._privateTestField
end end
"; ";
Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options); Assert.Throws<ParseException>(() => Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options));
} }
[Fact] [Fact]
@ -118,7 +119,7 @@ function test(o)
o.GetOnly = true o.GetOnly = true
end end
"; ";
Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options); Assert.Throws<ParseException>(() => Executor.EvaluateFunction(input, "test", new[] {obj}, Options));
Assert.False(obj.GetOnly); Assert.False(obj.GetOnly);
} }
@ -131,7 +132,7 @@ function test(o)
o.PrivateSet = true o.PrivateSet = true
end end
"; ";
Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options); Assert.Throws<ParseException>(() => Executor.EvaluateFunction<string>(input, "test", new[] {obj}, Options));
Assert.False(obj.PrivateSet); Assert.False(obj.PrivateSet);
} }

View File

@ -15,7 +15,7 @@ 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(true)", Options)); Assert.Throws<Exception>(() => Executor.EvaluateScript("assert(false)", Options));
} }
[Fact] [Fact]

View File

@ -13,7 +13,10 @@ namespace Ycicle
{ {
Console.WriteLine("Upsilon REPL"); Console.WriteLine("Upsilon REPL");
Script script = null; Script script = null;
var (evaluationScope, boundScope) = StaticScope.CreateStandardLibrary(); var options = new ScriptOptions()
{
ThrowExceptionOnError = false
};
while (true) while (true)
{ {
@ -21,7 +24,7 @@ namespace Ycicle
var input = Console.ReadLine(); var input = Console.ReadLine();
if (input == "exit") return; if (input == "exit") return;
script = script == null script = script == null
? Executor.ParseInput(input) ? Executor.ParseInput(input, options)
: Executor.ContinueWith(script, input); : Executor.ContinueWith(script, input);
if (script.Diagnostics.Messages.Count > 0) if (script.Diagnostics.Messages.Count > 0)