diff --git a/Upsilon/BaseTypes/ScriptFunction/ScriptMethodInfoFunction.cs b/Upsilon/BaseTypes/ScriptFunction/ScriptMethodInfoFunction.cs index 9557ad1..f5104d2 100644 --- a/Upsilon/BaseTypes/ScriptFunction/ScriptMethodInfoFunction.cs +++ b/Upsilon/BaseTypes/ScriptFunction/ScriptMethodInfoFunction.cs @@ -107,11 +107,9 @@ namespace Upsilon.BaseTypes.ScriptFunction // if we haven't found a method, we throw an exception if (method == null) { - var (i, pos) = diagnostics.ScriptString.GetLinePosition(span.Start); - var line = diagnostics.ScriptString.GetLine(i); throw new ScriptRuntimeException( $"Can't find method {_method.Name} with parameter types {string.Join(", ", convertedTypes.Select(x => x.Name))} on type {_object.GetType().Name}", - i, pos, line); + span, diagnostics.ScriptString.GetSpan(span)); } // get the method parameters var parameters = method.GetParameters(); diff --git a/Upsilon/BaseTypes/UserData/ListUserData.cs b/Upsilon/BaseTypes/UserData/ListUserData.cs index 4c0cf41..6eb8a4c 100644 --- a/Upsilon/BaseTypes/UserData/ListUserData.cs +++ b/Upsilon/BaseTypes/UserData/ListUserData.cs @@ -51,11 +51,9 @@ namespace Upsilon.BaseTypes.UserData } else { - var (i, pos) = diagnostics.ScriptString.GetLinePosition(span.Start); - var line = diagnostics.ScriptString.GetLine(i); throw new ScriptRuntimeException( $"Tried indexing a CSharp list with a value that's not an integer. Value: {scriptIndex.ToCSharpObject()}", - i, pos, line); + span, diagnostics.ScriptString.GetSpan(span)); } index--; diff --git a/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs b/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs index b0f1e8b..1aecadb 100644 --- a/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs @@ -17,18 +17,18 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundBinaryExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int line, int character) { - if (characterPosition >= LeftExpression.Span.Start && characterPosition <= LeftExpression.Span.End) + if (LeftExpression.Span.Contains(line, character)) { - foreach (var exp in LeftExpression.GetNodeAtPosition(characterPosition)) + foreach (var exp in LeftExpression.GetNodeAtPosition(line, character)) { yield return exp; } } - if (characterPosition >= RightExpression.Span.Start && characterPosition <= RightExpression.Span.End) + if (RightExpression.Span.Contains(line, character)) { - foreach (var exp in RightExpression.GetNodeAtPosition(characterPosition)) + foreach (var exp in RightExpression.GetNodeAtPosition(line, character)) { yield return exp; } diff --git a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs index e16a418..338ae2f 100644 --- a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs @@ -19,20 +19,25 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundFunctionCallExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int line, int character) { - if (characterPosition >= Identifier.Span.Start && characterPosition <= Identifier.Span.End) + if (Identifier.Span.Contains(line, character)) { - foreach (var exp in Identifier.GetNodeAtPosition(characterPosition)) + foreach (var exp in Identifier.GetNodeAtPosition(line, character)) { yield return exp; } + } foreach (var parameter in Parameters) { - if (characterPosition >= parameter.Span.Start && characterPosition <= parameter.Span.End) + if (parameter.Span.Contains(line, character)) { - foreach (var boundNode in parameter.GetNodeAtPosition(characterPosition)) yield return boundNode; + foreach (var exp in parameter.GetNodeAtPosition(line, character)) + { + yield return exp; + } + } } yield return this; diff --git a/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs b/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs index 488e3a7..17c62b5 100644 --- a/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs @@ -20,17 +20,21 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundFunctionExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { foreach (var parameter in Parameters) { - if (characterPosition >= parameter.Span.Start && characterPosition <= parameter.Span.End) - foreach (var boundNode in parameter.GetNodeAtPosition(characterPosition)) + if (parameter.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in parameter.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; + } } - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + if (Block.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; + } yield return this; } diff --git a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs index 335781b..dc9ddac 100644 --- a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs @@ -18,16 +18,18 @@ namespace Upsilon.Binder public BoundExpression Index { get; } public override BoundKind Kind => BoundKind.BoundIndexExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Identifier.Span.Start && characterPosition <= Identifier.Span.End) - foreach (var boundNode in Identifier.GetNodeAtPosition(characterPosition)) + if (Identifier.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Identifier.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Index.Span.Start && characterPosition <= Index.Span.End) - foreach (var boundNode in Index.GetNodeAtPosition(characterPosition)) + } + if (Index.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Index.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - + } yield return this; } @@ -47,12 +49,15 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Expression.Span.Start && characterPosition <= Expression.Span.End) - foreach (var boundNode in Expression.GetNodeAtPosition(characterPosition)) + if (Expression.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Expression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; + } + yield return this; } diff --git a/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs b/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs index a42972d..c4ca7ae 100644 --- a/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs @@ -12,7 +12,7 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundLiteralExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int line, int character) { yield return this; } diff --git a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs index 47c2181..1865807 100644 --- a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs @@ -17,16 +17,16 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundTableExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { foreach (var statement in Statements) { - if (characterPosition >= statement.Span.Start && characterPosition <= statement.Span.End) - foreach (var boundNode in statement.GetNodeAtPosition(characterPosition)) - yield return boundNode; + if (statement.Span.Contains(linePosition, characterPosition)) + { + yield return statement; + } } yield return this; - } public override Type Type => Type.Table; diff --git a/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs b/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs index 3e5019e..168e6fe 100644 --- a/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs @@ -7,12 +7,13 @@ namespace Upsilon.Binder public class BoundUnaryExpression : BoundExpression { public override BoundKind Kind => BoundKind.BoundUnaryExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= InExpression.Span.Start && characterPosition <= InExpression.Span.End) - foreach (var boundNode in InExpression.GetNodeAtPosition(characterPosition)) + if (InExpression.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in InExpression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - + } yield return this; } diff --git a/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs index 8bb3fa0..551e39c 100644 --- a/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs @@ -14,7 +14,7 @@ namespace Upsilon.Binder public BoundVariableSymbol Variable { get; } public override BoundKind Kind => BoundKind.VariableExpression; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { yield return Variable; } diff --git a/Upsilon/Binder/BoundNode.cs b/Upsilon/Binder/BoundNode.cs index 6a5b559..41ec278 100644 --- a/Upsilon/Binder/BoundNode.cs +++ b/Upsilon/Binder/BoundNode.cs @@ -13,6 +13,6 @@ namespace Upsilon.Binder public abstract BoundKind Kind { get; } public TextSpan Span { get; } - public abstract IEnumerable GetNodeAtPosition(int characterPosition); + public abstract IEnumerable GetNodeAtPosition(int linePosition, int characterPosition); } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs b/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs index 8d54dfc..1b05f0c 100644 --- a/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs @@ -13,13 +13,17 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundBlockStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { foreach (var statement in Statements) { - if (characterPosition >= statement.Span.Start && characterPosition <= statement.Span.End) - foreach (var boundNode in statement.GetNodeAtPosition(characterPosition)) - yield return boundNode; + if (statement.Span.Contains(linePosition, characterPosition)) + { + foreach (var node in statement.GetNodeAtPosition(linePosition, characterPosition)) + { + yield return node; + } + } } yield return this; } diff --git a/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs b/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs index 06f56cd..6e27655 100644 --- a/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs @@ -10,11 +10,9 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundBreakStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Span.Start && characterPosition <= Span.End) - yield return this; - yield return null; + yield return this; } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs b/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs index a0dec05..62b9d42 100644 --- a/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs @@ -7,13 +7,11 @@ namespace Upsilon.Binder { public BoundExpression Expression { get; } public override BoundKind Kind => BoundKind.BoundExpressionStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Span.Start && characterPosition <= Span.End) - foreach (var boundNode in Expression.GetNodeAtPosition(characterPosition)) - yield return boundNode; + foreach (var boundNode in Expression.GetNodeAtPosition(linePosition, characterPosition)) + yield return boundNode; - yield return this; } public BoundExpressionStatement(BoundExpression expression, TextSpan span):base(span) diff --git a/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs index 0104e74..9f09359 100644 --- a/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs @@ -16,10 +16,10 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundFunctionAssignmentStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Func.Span.Start && characterPosition <= Func.Span.End) - foreach (var boundNode in Func.GetNodeAtPosition(characterPosition)) + if (Func.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Func.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; yield return this; diff --git a/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs b/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs index 2bfd7c9..60b0550 100644 --- a/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs @@ -20,16 +20,18 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundGenericForStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= BoundEnumerableExpression.Span.Start && characterPosition <= BoundEnumerableExpression.Span.End) - foreach (var boundNode in BoundEnumerableExpression.GetNodeAtPosition(characterPosition)) + if (BoundEnumerableExpression.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in BoundEnumerableExpression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + } + if (Block.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - + } yield return this; } } diff --git a/Upsilon/Binder/BoundStatements/BoundIfStatement.cs b/Upsilon/Binder/BoundStatements/BoundIfStatement.cs index 00cce71..2cd3ccd 100644 --- a/Upsilon/Binder/BoundStatements/BoundIfStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundIfStatement.cs @@ -25,24 +25,28 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundIfStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Condition.Span.Start && characterPosition <= Condition.Span.End) - foreach (var boundNode in Condition.GetNodeAtPosition(characterPosition)) + if (Condition.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Condition.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + } + if (Block.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (NextElseIf != null && characterPosition >= NextElseIf.Span.Start && characterPosition <= NextElseIf.Span.End) - foreach (var boundNode in NextElseIf.GetNodeAtPosition(characterPosition)) + } + if (NextElseIf != null && NextElseIf.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in NextElseIf.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (ElseStatement != null && characterPosition >= ElseStatement.Span.Start && characterPosition <= ElseStatement.Span.End) - foreach (var boundNode in ElseStatement.GetNodeAtPosition(characterPosition)) + } + if (ElseStatement != null && ElseStatement.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in ElseStatement.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - + } yield return this; } @@ -62,12 +66,13 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundElseStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (Block != null && characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + if (Block.Span.Contains(linePosition, characterPosition)) + { + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - + } yield return this; } } diff --git a/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs index af136a7..1fb1a25 100644 --- a/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs @@ -18,14 +18,13 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundMultiAssignmentStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Assignment.Span.Start && characterPosition <= Assignment.Span.End) - foreach (var boundNode in Assignment.GetNodeAtPosition(characterPosition)) + if (Assignment.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Assignment.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; yield return this; - } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs b/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs index cb25589..147d2d0 100644 --- a/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs @@ -23,26 +23,21 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundNumericForStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= BoundStart.Span.Start && characterPosition <= BoundStart.Span.End) - foreach (var boundNode in BoundStart.GetNodeAtPosition(characterPosition)) + if (BoundStart.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in BoundStart.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= BoundStop.Span.Start && characterPosition <= BoundStop.Span.End) - foreach (var boundNode in BoundStop.GetNodeAtPosition(characterPosition)) + if (BoundStop.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in BoundStop.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= BoundStep.Span.Start && characterPosition <= BoundStep.Span.End) - foreach (var boundNode in BoundStep.GetNodeAtPosition(characterPosition)) + if (BoundStep.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in BoundStep.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + if (Block.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - yield return this; - } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs b/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs index 4c5c013..cd62c5c 100644 --- a/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs @@ -12,12 +12,11 @@ namespace Upsilon.Binder public BoundExpression Expression { get; } public override BoundKind Kind => BoundKind.BoundReturnStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Expression.Span.Start && characterPosition <= Expression.Span.End) - foreach (var boundNode in Expression.GetNodeAtPosition(characterPosition)) + if (Expression.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Expression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - yield return this; } } diff --git a/Upsilon/Binder/BoundStatements/BoundScript.cs b/Upsilon/Binder/BoundStatements/BoundScript.cs index 0e5fc3e..9f6448f 100644 --- a/Upsilon/Binder/BoundStatements/BoundScript.cs +++ b/Upsilon/Binder/BoundStatements/BoundScript.cs @@ -7,7 +7,7 @@ namespace Upsilon.Binder public class BoundScript : BoundStatement { public Script Script { get; } - + public BoundScript(BoundBlockStatement statement, TextSpan span, BoundScope scope, string fileName, Script script) : base(span) { Statement = statement; @@ -18,9 +18,9 @@ namespace Upsilon.Binder public string FileName { get; set; } public override BoundKind Kind => BoundKind.BoundScript; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - foreach (var boundNode in Statement.GetNodeAtPosition(characterPosition)) yield return boundNode; + foreach (var boundNode in Statement.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; } public BoundBlockStatement Statement { get; } diff --git a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs index 704c116..7988f45 100644 --- a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs @@ -16,18 +16,15 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundTableAssigmentStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= TableIndexExpression.Span.Start && characterPosition <= TableIndexExpression.Span.End) - foreach (var boundNode in TableIndexExpression.GetNodeAtPosition(characterPosition)) + if (TableIndexExpression.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in TableIndexExpression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Value.Span.Start && characterPosition <= Value.Span.End) - foreach (var boundNode in Value.GetNodeAtPosition(characterPosition)) + if (Value.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Value.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - yield return this; - } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs b/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs index d21ea95..14b2d9b 100644 --- a/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs +++ b/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs @@ -18,16 +18,15 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundAssignmentStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Variable.Span.Start && characterPosition <= Variable.Span.End) + if (Variable.Span.Contains(linePosition, characterPosition)) yield return Variable; - if (characterPosition >= BoundExpression.Span.Start && characterPosition <= BoundExpression.Span.End) - foreach (var boundNode in BoundExpression.GetNodeAtPosition(characterPosition)) + if (BoundExpression.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in BoundExpression.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; yield return this; - } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs b/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs index 426baa4..3e2fd68 100644 --- a/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs @@ -17,16 +17,14 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundWhileStatement; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { - if (characterPosition >= Condition.Span.Start && characterPosition <= Condition.Span.End) - foreach (var boundNode in Condition.GetNodeAtPosition(characterPosition)) + if (Condition.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Condition.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + if (Block.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; - yield return this; } } diff --git a/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs b/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs index f2f3f95..b48e65e 100644 --- a/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs +++ b/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs @@ -19,19 +19,19 @@ namespace Upsilon.Binder public BlockStatementSyntax UnboundBlock { get; } - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int linePosition, int characterPosition) { foreach (var parameter in Parameters) { - if (characterPosition >= parameter.Span.Start && characterPosition <= parameter.Span.End) - foreach (var boundNode in parameter.GetNodeAtPosition(characterPosition)) + if (parameter.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in parameter.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; } if (Block != null) { - if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) - foreach (var boundNode in Block.GetNodeAtPosition(characterPosition)) + if (Block.Span.Contains(linePosition, characterPosition)) + foreach (var boundNode in Block.GetNodeAtPosition(linePosition, characterPosition)) yield return boundNode; } yield return this; diff --git a/Upsilon/Binder/BoundVariableSymbol.cs b/Upsilon/Binder/BoundVariableSymbol.cs index 7bda29d..cae6dbb 100644 --- a/Upsilon/Binder/BoundVariableSymbol.cs +++ b/Upsilon/Binder/BoundVariableSymbol.cs @@ -17,7 +17,7 @@ namespace Upsilon.Binder public bool IsCreation { get; } public override BoundKind Kind => BoundKind.BoundVariableSymbol; - public override IEnumerable GetNodeAtPosition(int characterPosition) + public override IEnumerable GetNodeAtPosition(int characterPosition, int i) { yield return this; } diff --git a/Upsilon/Diagnostics.cs b/Upsilon/Diagnostics.cs index 4a693e8..cb23f71 100644 --- a/Upsilon/Diagnostics.cs +++ b/Upsilon/Diagnostics.cs @@ -33,9 +33,8 @@ namespace Upsilon { if (ThrowsOnError) { - var linePos = ScriptString.GetLinePosition(location.Start); - var line = ScriptString.GetLine(linePos.Line); - throw new ParseException(FileName, message, linePos.Line, linePos.Pos, line); + var text = ScriptString.GetSpan(location); + throw new ParseException(FileName, message, location.StartLine, location.StartPosition, text); } Log(DiagnosticLevel.Error, message, location); } @@ -122,39 +121,24 @@ namespace Upsilon Span = span; } - public (int Position, int PositionOnLine) GetStartLine() - { - return Diagnostics.ScriptString.GetLinePosition(Span.Start); - } - - public (int Position, int PositionOnLine) GetEndLine() - { - return Diagnostics.ScriptString.GetLinePosition(Span.End); - } - - public override string ToString() { - var linePos = Diagnostics.ScriptString.GetLinePosition(Span.Start); - return $"{Message} at ({linePos.Line}, {linePos.Pos})\n{Diagnostics.ScriptString.GetSpan(Span)}"; + return $"{Message} at ({Span.StartLine}, {Span.StartPosition})\n{Diagnostics.ScriptString.GetSpan(Span)}"; } public string GetDiagnosticPosition() { - var linePos = Diagnostics.ScriptString.GetLinePosition(Span.Start); - return $"({linePos.Line},{linePos.Pos})"; + return $"({Span.StartLine},{Span.StartPosition})"; } public string LineBeforeError() { - var linePos = Diagnostics.ScriptString.GetLinePosition(Span.Start); - var lineIndex = Diagnostics.ScriptString.GetLineStartPos(linePos.Line); - return Diagnostics.ScriptString.GetSpan(lineIndex, linePos.Pos); + return Diagnostics.ScriptString.GetSpan(Span.StartLine, 0, Span.StartLine, Span.StartPosition); } public string BeforeError(int i = 5) { - return Diagnostics.ScriptString.GetSpan(Span.Start - i, i); + return Diagnostics.ScriptString.GetSpan(Span.StartLine, Span.StartPosition - i, Span.StartLine, Span.StartPosition); } public string AtError() @@ -164,15 +148,12 @@ namespace Upsilon public string LineAfterError() { - var linePos = Diagnostics.ScriptString.GetLinePosition(Span.Start); - var lineInfo = Diagnostics.ScriptString.GetLineInfo(linePos.Line); - - return Diagnostics.ScriptString.GetSpan(Span.End, lineInfo.End - Span.End); + return Diagnostics.ScriptString.GetSpan(Span.EndLine, Span.EndPosition, Span.EndLine, 10000); } public string AfterError(int i = 5) { - return Diagnostics.ScriptString.GetSpan(Span.Start + Span.Length, i); + return Diagnostics.ScriptString.GetSpan(Span.EndLine, Span.EndPosition, Span.EndLine, Span.EndPosition + i); } } diff --git a/Upsilon/Evaluator/Debugging/DebugFile.cs b/Upsilon/Evaluator/Debugging/DebugFile.cs index 0dc3ff7..5985a47 100644 --- a/Upsilon/Evaluator/Debugging/DebugFile.cs +++ b/Upsilon/Evaluator/Debugging/DebugFile.cs @@ -10,5 +10,6 @@ namespace Upsilon.Evaluator.Debugging public class Breakpoint { public int Line { get; set; } + public int Position { get; set; } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index f4ab525..95d9aba 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -67,8 +67,7 @@ namespace Upsilon.Evaluator { foreach (var breakpoint in file.Breakpoints) { - var lineStart = _script.ScriptString.GetLineInfo(breakpoint.Line).Start; - var debugStatement = e.GetBottomStatementAtPosition(lineStart); + var debugStatement = e.GetBottomStatementAtPosition(breakpoint.Line, breakpoint.Position); debugStatement.HasBreakpoint = true; } } @@ -436,9 +435,7 @@ namespace Upsilon.Evaluator private void ThrowException(string message, TextSpan location) { - var (i, pos) = _script.ScriptString.GetLinePosition(location.Start); - var line = _script.ScriptString.GetLine(i); - throw new ScriptRuntimeException(message, i, pos, line); + throw new ScriptRuntimeException(message, location, _diagnostics.ScriptString.GetSpan(location)); } private void EvaluateAssignmentStatement(BoundVariableAssignment e) diff --git a/Upsilon/Exceptions/ScriptRuntimeException.cs b/Upsilon/Exceptions/ScriptRuntimeException.cs index 883ddf6..3767cfb 100644 --- a/Upsilon/Exceptions/ScriptRuntimeException.cs +++ b/Upsilon/Exceptions/ScriptRuntimeException.cs @@ -1,4 +1,5 @@ using System; +using Upsilon.Text; namespace Upsilon.Exceptions { @@ -9,11 +10,11 @@ namespace Upsilon.Exceptions public int Character { get; } public string ErrorLine { get; } - public ScriptRuntimeException(string errorMessage, int line, int character, string errorLine) + public ScriptRuntimeException(string errorMessage, TextSpan position, string errorLine) { ErrorMessage = errorMessage; - Line = line; - Character = character; + Line = position.StartLine; + Character = position.StartPosition; ErrorLine = errorLine; } diff --git a/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs index 769976b..b8013cb 100644 --- a/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/BinaryExpressionSyntax.cs @@ -10,7 +10,7 @@ namespace Upsilon.Parser Left = left; Operator = @operator; Right = right; - Span = new TextSpan(left.Span.Start, right.Span.End - left.Span.Start); + Span = TextSpan.Between(left.Span, right.Span); } public override SyntaxKind Kind => SyntaxKind.BinaryExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs index 76a7d3c..19df90f 100644 --- a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs @@ -18,7 +18,7 @@ namespace Upsilon.Parser OpenParenthesis = openParenthesis; Parameters = parameters; CloseParenthesis = closeParenthesis; - Span = new TextSpan(Identifier.Span.Start, CloseParenthesis.Span.End - Identifier.Span.Start); + Span = TextSpan.Between(Identifier.Span, CloseParenthesis.Span); } public override SyntaxKind Kind => SyntaxKind.FunctionCallExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs index fc729eb..e5cc313 100644 --- a/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs @@ -23,7 +23,7 @@ namespace Upsilon.Parser CloseParenthesis = closeParenthesis; Block = block; EndToken = endToken; - Span = new TextSpan(FunctionToken.Span.Start, EndToken.Span.End - FunctionToken.Span.Start); + Span = TextSpan.Between(FunctionToken.Span, endToken.Span); } public override SyntaxKind Kind => SyntaxKind.FunctionExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs index 6b460a7..b132070 100644 --- a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs @@ -17,7 +17,7 @@ namespace Upsilon.Parser OpenBracket = openBracket; Index = index; CloseBracket = closeBracket; - Span = new TextSpan(expression.Span.Start, CloseBracket.Span.End - expression.Span.Start); + Span = TextSpan.Between(expression.Span, closeBracket.Span); } public override SyntaxKind Kind => SyntaxKind.IndexExpression; @@ -41,7 +41,7 @@ namespace Upsilon.Parser Expression = expression; FullStop = fullStop; Index = index; - Span = new TextSpan(expression.Span.Start, Index.Span.End - expression.Span.Start); + Span = TextSpan.Between(expression.Span, Index.Span); } public override SyntaxKind Kind => SyntaxKind.FullStopIndexExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs index c679bfe..0c3c5bc 100644 --- a/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs @@ -10,7 +10,7 @@ namespace Upsilon.Parser OpenParenthesis = openParenthesis; Expression = expression; CloseParenthesis = closeParenthesis; - Span = new TextSpan(OpenParenthesis.Span.Start, CloseParenthesis.Span.End - OpenParenthesis.Span.Start); + Span = TextSpan.Between(OpenParenthesis.Span, CloseParenthesis.Span); } public override SyntaxKind Kind => SyntaxKind.ParenthesizedExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs index b5d1b8d..0612a4c 100644 --- a/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs @@ -11,7 +11,7 @@ namespace Upsilon.Parser Expressions = expressions; OpenBrace = openBrace; CloseBrace = closeBrace; - Span = new TextSpan(OpenBrace.Span.Start, CloseBrace.Span.End - OpenBrace.Span.Start); + Span = TextSpan.Between(OpenBrace.Span, CloseBrace.Span); } public override SyntaxKind Kind => SyntaxKind.TableExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs index 098fdbc..b691b50 100644 --- a/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs @@ -9,7 +9,7 @@ namespace Upsilon.Parser { Operator = @operator; Expression = expression; - Span = new TextSpan(Operator.Span.Start, expression.Span.End - Operator.Span.Start); + Span = TextSpan.Between(Operator.Span, expression.Span); } public override SyntaxKind Kind => SyntaxKind.UnaryExpression; diff --git a/Upsilon/Parser/IdentifierToken.cs b/Upsilon/Parser/IdentifierToken.cs index 67620de..85ccdb7 100644 --- a/Upsilon/Parser/IdentifierToken.cs +++ b/Upsilon/Parser/IdentifierToken.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { public class IdentifierToken : SyntaxToken { - public IdentifierToken(string name, int position) + public IdentifierToken(string name, TextSpan position) : base(SyntaxKind.Identifier, position, name, null) { Name = name; diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index 03d6050..3b436fe 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -9,14 +9,15 @@ namespace Upsilon.Parser public class Lexer { private bool SaveComments { get; } - private readonly string _text; + private readonly string[] _text; private readonly Diagnostics _diagnostics; + private int _linePosition; private int _position; private Lexer(string text, Diagnostics diagnostics, bool saveComments) { SaveComments = saveComments; - _text = text; + _text = text.Split('\n'); _diagnostics = diagnostics; } @@ -26,8 +27,29 @@ namespace Upsilon.Parser return lexer.Lex(); } - private char Current => _position >= _text.Length ? '\0' : _text[_position]; - private char Next => _position + 1 >= _text.Length ? '\0' : _text[_position + 1]; + private char Current + { + get + { + var linePos = _linePosition; + var pos = _position; + if (linePos >= _text.Length) return '\0'; + if (pos >= _text[linePos].Length) return '\n'; + return _text[linePos][pos]; + } + } + + private char Next + { + get + { + var linePos = _linePosition; + var pos = _position + 1; + if (linePos >= _text.Length) return '\0'; + if (pos >= _text[linePos].Length) return '\n'; + return _text[linePos][pos]; + } + } private readonly List _activeComments = new List(); private ImmutableArray Lex() @@ -66,46 +88,53 @@ namespace Upsilon.Parser switch (Current) { case '\0': - return new SyntaxToken(SyntaxKind.EndOfFile, _position, "\0", null); - case ' ': case '\t': case '\r': case '\n': - return new SyntaxToken(SyntaxKind.WhiteSpace, _position, Current.ToString(), null); + return new SyntaxToken(SyntaxKind.EndOfFile, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "\0", null); + case ' ': case '\t': case '\r': + return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), Current.ToString(), null); + case '\n': + { + _linePosition++; + var pos = _position; + _position = -1; + return new SyntaxToken(SyntaxKind.WhiteSpace, new TextSpan(_linePosition, pos, _linePosition, pos + 1), "\n", null); + } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return LexNumber(); case '+': - return new SyntaxToken(SyntaxKind.Plus, _position, "+", null); + return new SyntaxToken(SyntaxKind.Plus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "+", null); case '-': if (Next == '-') { _position++; return LexComments(); } - return new SyntaxToken(SyntaxKind.Minus, _position, "-", null); + return new SyntaxToken(SyntaxKind.Minus, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "-", null); case '*': - return new SyntaxToken(SyntaxKind.Star, _position, "*", null); + return new SyntaxToken(SyntaxKind.Star, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "*", null); case '/': - return new SyntaxToken(SyntaxKind.Slash, _position, "/", null); + return new SyntaxToken(SyntaxKind.Slash, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "/", null); case '(': - return new SyntaxToken(SyntaxKind.OpenParenthesis, _position, "(", null); + return new SyntaxToken(SyntaxKind.OpenParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "(", null); case ')': - return new SyntaxToken(SyntaxKind.CloseParenthesis, _position, ")", null); + return new SyntaxToken(SyntaxKind.CloseParenthesis, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ")", null); case '{': - return new SyntaxToken(SyntaxKind.OpenBrace, _position, "{", null); + return new SyntaxToken(SyntaxKind.OpenBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "{", null); case '}': - return new SyntaxToken(SyntaxKind.CloseBrace, _position, "}", null); + return new SyntaxToken(SyntaxKind.CloseBrace, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "}", null); case '[': - return new SyntaxToken(SyntaxKind.OpenBracket, _position, "[", null); + return new SyntaxToken(SyntaxKind.OpenBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "[", null); case ']': - return new SyntaxToken(SyntaxKind.CloseBracket, _position, "]", null); + return new SyntaxToken(SyntaxKind.CloseBracket, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "]", null); case '.': - return new SyntaxToken(SyntaxKind.FullStop, _position, ".", null); + return new SyntaxToken(SyntaxKind.FullStop, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ".", null); case ',': - return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); + return new SyntaxToken(SyntaxKind.Comma, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ",", null); case '#': - return new SyntaxToken(SyntaxKind.PoundSign, _position, "#", null); + return new SyntaxToken(SyntaxKind.PoundSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "#", null); case '%': - return new SyntaxToken(SyntaxKind.PercentSign, _position, "%", null); + return new SyntaxToken(SyntaxKind.PercentSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "%", null); case '^': - return new SyntaxToken(SyntaxKind.RoofSign, _position, "^", null); + return new SyntaxToken(SyntaxKind.RoofSign, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "^", null); case '"': case '\'': return LexString(Current); @@ -113,35 +142,35 @@ namespace Upsilon.Parser if (Next == '=') { _position++; - return new SyntaxToken(SyntaxKind.EqualsEquals, _position - 1, "==", null); + return new SyntaxToken(SyntaxKind.EqualsEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "==", null); } - return new SyntaxToken(SyntaxKind.Equals, _position, "=", null); + return new SyntaxToken(SyntaxKind.Equals, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "=", null); case '~': if (Next == '=') { _position++; - return new SyntaxToken(SyntaxKind.TildeEquals, _position - 1, "~=", null); + return new SyntaxToken(SyntaxKind.TildeEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "~=", null); } - return new SyntaxToken(SyntaxKind.Tilde, _position, "~", null); + return new SyntaxToken(SyntaxKind.Tilde, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "~", null); case '<': if (Next == '=') { _position++; - return new SyntaxToken(SyntaxKind.LessEquals, _position - 1, "<=", null); + return new SyntaxToken(SyntaxKind.LessEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), "<=", null); } - return new SyntaxToken(SyntaxKind.Less, _position, "<", null); + return new SyntaxToken(SyntaxKind.Less, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "<", null); case '>': if (Next == '=') { _position++; - return new SyntaxToken(SyntaxKind.GreaterEquals, _position - 1, ">=", null); + return new SyntaxToken(SyntaxKind.GreaterEquals, new TextSpan(_linePosition, _position - 1, _linePosition, _position + 1), ">=", null); } - return new SyntaxToken(SyntaxKind.Greater, _position, ">", null); + return new SyntaxToken(SyntaxKind.Greater, new TextSpan(_linePosition, _position, _linePosition, _position + 1), ">", null); default: if (char.IsLetter(Current) || Current == '_') return LexIdentifierOrKeyword(); - _diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Identifier); - return new SyntaxToken(SyntaxKind.BadToken, _position, "", null); + _diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Identifier); + return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "", null); } } @@ -157,8 +186,8 @@ namespace Upsilon.Parser { if (hasDecimalPoint) { - _diagnostics.LogBadCharacter(new TextSpan(_position, 1), SyntaxKind.Number); - return new SyntaxToken(SyntaxKind.BadToken, _position, "", null); + _diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), SyntaxKind.Number); + return new SyntaxToken(SyntaxKind.BadToken, new TextSpan(_linePosition, _position, _linePosition, _position + 1), "", null); } hasDecimalPoint = true; } @@ -172,16 +201,18 @@ namespace Upsilon.Parser o = double.Parse(numStr.ToString()); else o = long.Parse(numStr.ToString()); - return new SyntaxToken(SyntaxKind.Number, start, numStr.ToString(), o); + return new SyntaxToken(SyntaxKind.Number, new TextSpan(_linePosition, start, _linePosition, _position + 1), numStr.ToString(), o); } private SyntaxToken LexString(char current) { var start = _position; var sb = new StringBuilder(); - while (_position < _text.Length) + while (true) { _position++; + if (Current == '\0') + break; if (Current == '\\' && Next == current) { sb.Append(current); @@ -194,15 +225,18 @@ namespace Upsilon.Parser if (Current != current) { - _diagnostics.LogBadCharacter(new TextSpan(_position, 1), current, Current); + _diagnostics.LogBadCharacter(new TextSpan(_linePosition, _position, _linePosition, _position + 1), + current, Current); } var res = sb.ToString(); - return new SyntaxToken(SyntaxKind.String, start, $"\"{res}\"", res); + return new SyntaxToken(SyntaxKind.String, new TextSpan(_linePosition, start, _linePosition, _position + 1), + $"\"{res}\"", res); } private SyntaxToken LexIdentifierOrKeyword() { + var startLine = _linePosition; var start = _position; var stringBuilder = new StringBuilder(); stringBuilder.Append(Current); @@ -216,19 +250,20 @@ namespace Upsilon.Parser var str = stringBuilder.ToString(); if (kind == SyntaxKind.Identifier) { - return new IdentifierToken(str, start); + return new IdentifierToken(str, new TextSpan(startLine, start, _linePosition, _position)); } if (kind == SyntaxKind.ReturnKeyword) { - return new ReturnSyntaxToken(start, Next == Environment.NewLine[0]); + return new ReturnSyntaxToken(new TextSpan(_linePosition, start, _linePosition, _position + 1), Next == Environment.NewLine[0]); } - return new SyntaxToken(kind, start, str, null); + return new SyntaxToken(kind, new TextSpan(_linePosition, start, _linePosition, _position + 1), str, null); } private SyntaxToken LexComments() { _position++; + var startLine = _linePosition; var start = _position; StringBuilder stringBuilder = null; if (SaveComments) @@ -244,7 +279,7 @@ namespace Upsilon.Parser } var str = stringBuilder?.ToString(); _position++; - return new SyntaxToken(SyntaxKind.Comment, start, _position - start, str); + return new SyntaxToken(SyntaxKind.Comment, new TextSpan(startLine, start, _linePosition, _position + 1), _position - start, str); } } } \ No newline at end of file diff --git a/Upsilon/Parser/ParameterToken.cs b/Upsilon/Parser/ParameterToken.cs index 179131b..324115f 100644 --- a/Upsilon/Parser/ParameterToken.cs +++ b/Upsilon/Parser/ParameterToken.cs @@ -9,9 +9,9 @@ namespace Upsilon.Parser { TypeName = typeName; IdentifierName = identifierName; - var start = identifierName.Span.Start; - if (typeName != null) start = typeName.Span.Start; - Span = new TextSpan(start, identifierName.Span.End - start); + var start = identifierName.Span; + if (typeName != null) start = typeName.Span; + Span = TextSpan.Between(start, identifierName.Span); } public IdentifierToken TypeName { get; } diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 4c725ef..c2ccb97 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -29,7 +29,7 @@ namespace Upsilon.Parser private SyntaxToken Get(int offset) { if (_position + offset >= _tokens.Length) - return new SyntaxToken(SyntaxKind.EndOfFile, _position + offset, "\0", null); + return new SyntaxToken(SyntaxKind.EndOfFile, _tokens.Last().Span, "\0", null); else { return _tokens[_position + offset]; @@ -49,7 +49,7 @@ namespace Upsilon.Parser return NextToken(); _diagnostics.LogBadCharacter(Current.Span, kind, Current.Kind); - return new SyntaxToken(kind, Current.Span.Start, "", null); + return new SyntaxToken(kind, Current.Span, "", null); } private StatementSyntax ParseScriptSyntax() @@ -515,7 +515,7 @@ namespace Upsilon.Parser // We'll still want to return a index expression, but we just express that the identifier is empty. // This is helpful for tools, etc return new FullStopIndexExpressionSyntax(expression, fullStop, - new IdentifierToken(string.Empty, fullStop.Span.End)); + new IdentifierToken(string.Empty, fullStop.Span)); } private ExpressionSyntax ParseParenthesizedExpression() diff --git a/Upsilon/Parser/StatementSyntax/AssignmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/AssignmentStatementSyntax.cs index ca97cb2..0865f2a 100644 --- a/Upsilon/Parser/StatementSyntax/AssignmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/AssignmentStatementSyntax.cs @@ -12,8 +12,8 @@ namespace Upsilon.Parser Identifier = identifyExpression; EqualsToken = equalsToken; Expression = expression; - var start = LocalToken?.Span.Start ?? Identifier.Span.Start; - Span = new TextSpan(start, Expression.Span.End - start); + var start = LocalToken?.Span ?? Identifier.Span; + Span = TextSpan.Between(start, expression.Span); } public override SyntaxKind Kind => SyntaxKind.AssignmentStatement; diff --git a/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs index 2b6c555..615a19b 100644 --- a/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/BlockStatementSyntax.cs @@ -13,7 +13,7 @@ namespace Upsilon.Parser var first = statements.FirstOrDefault(); var last = statements.LastOrDefault(); if (first != null && last != null) - Span = new TextSpan(first.Span.Start, last.Span.End - first.Span.Start); + Span = TextSpan.Between(first.Span, last.Span); } public ImmutableArray Statements { get; } diff --git a/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs index 180aec5..7500de6 100644 --- a/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs @@ -10,9 +10,9 @@ namespace Upsilon.Parser LocalToken = localToken; Identifier = identifier; FunctionExpression = functionExpression; - var start = Identifier.Span.Start; - if (localToken != null) start = localToken.Span.Start; - Span = new TextSpan(start, FunctionExpression.Span.End - start); + var start = Identifier.Span; + if (localToken != null) start = localToken.Span; + Span = TextSpan.Between(start, functionExpression.Span); } public SyntaxToken LocalToken { get; } diff --git a/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs index 22b5935..81bd9bc 100644 --- a/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs @@ -24,7 +24,7 @@ namespace Upsilon.Parser DoKeyword = doKeyword; Block = block; EndKeyword = endKeyword; - Span = new TextSpan(forKeyword.Span.Start, endKeyword.Span.End - forKeyword.Span.Start); + Span = TextSpan.Between(forKeyword.Span, endKeyword.Span); } public override SyntaxKind Kind => SyntaxKind.GenericForStatement; diff --git a/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs index b953478..72fca27 100644 --- a/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs @@ -16,9 +16,9 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; EndToken = endToken; - var end = Block.Span.End; - if (EndToken != null) end = EndToken.Span.End; - Span = new TextSpan(IfToken.Span.Start, end - IfToken.Span.Start); + var end = Block.Span; + if (EndToken != null) end = EndToken.Span; + Span = TextSpan.Between(ifToken.Span, end); } public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, @@ -29,7 +29,7 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; ElseStatement = elseStatement; - Span = new TextSpan(IfToken.Span.Start, ElseStatement.Span.End - IfToken.Span.Start); + Span = TextSpan.Between(ifToken.Span, elseStatement.Span); } public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, @@ -40,7 +40,7 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; NextElseIfStatement = nextElseIfStatement; - Span = new TextSpan(IfToken.Span.Start, NextElseIfStatement.Span.End - IfToken.Span.Start); + Span = TextSpan.Between(ifToken.Span, nextElseIfStatement.Span); } @@ -79,7 +79,7 @@ namespace Upsilon.Parser yield return Condition; yield return ThenToken; yield return Block; - Span = new TextSpan(ElseIfToken.Span.Start, Block.Span.End - ElseIfToken.Span.Start); + Span = TextSpan.Between(ElseIfToken.Span, Block.Span); } public ElseIfStatementSyntax(IfStatementSyntax s) @@ -119,7 +119,7 @@ namespace Upsilon.Parser ElseToken = elseToken; Block = block; EndToken = endToken; - Span = new TextSpan(ElseToken.Span.Start, EndToken.Span.End - ElseToken.Span.Start); + Span = TextSpan.Between(elseToken.Span, endToken.Span); } public override SyntaxKind Kind => SyntaxKind.ElseStatement; diff --git a/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs index dd98fa1..55aaa02 100644 --- a/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs @@ -19,9 +19,9 @@ namespace Upsilon.Parser Identifiers = identifiers.ToImmutableArray(); AssignmentToken = assignmentToken; Expression = expression; - var start = Identifiers.First().Span.Start; - if (localKeyword != null) start = localKeyword.Span.Start; - Span = new TextSpan(start, expression.Span.End - start); + var start = Identifiers.First().Span; + if (localKeyword != null) start = localKeyword.Span; + Span = TextSpan.Between(start, expression.Span); } public override SyntaxKind Kind => SyntaxKind.MultiAssignmentStatement; diff --git a/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs index f900ea5..107b1c5 100644 --- a/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs @@ -32,7 +32,7 @@ namespace Upsilon.Parser DoToken = doToken; Block = block; EndToken = endToken; - Span = new TextSpan(ForToken.Span.Start, EndToken.Span.End - ForToken.Span.Start); + Span = TextSpan.Between(forToken.Span, endToken.Span); } public override SyntaxKind Kind => SyntaxKind.NumericForStatement; diff --git a/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs index 4aba7de..7c9ebdc 100644 --- a/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs @@ -9,9 +9,9 @@ namespace Upsilon.Parser { ReturnToken = returnToken; Expression = expression; - var end = returnToken.Span.End; - if (expression != null) end = expression.Span.End; - Span = new TextSpan(returnToken.Span.Start, end - returnToken.Span.Start); + var end = returnToken.Span; + if (expression != null) end = expression.Span; + Span = TextSpan.Between(returnToken.Span, end); } public SyntaxToken ReturnToken { get; } diff --git a/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs index cf3a8b0..300c42c 100644 --- a/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs @@ -15,7 +15,7 @@ namespace Upsilon.Parser TableExpression = tableExpression; AssignmentToken = assignmentToken; Expression = expression; - Span = new TextSpan(tableExpression.Span.Start, expression.Span.End - tableExpression.Span.Start); + Span = TextSpan.Between(tableExpression.Span, expression.Span); } public override SyntaxKind Kind => SyntaxKind.TableAssignmentStatement; diff --git a/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs index 784d3be..c0eac04 100644 --- a/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/WhileStatementSyntax.cs @@ -21,7 +21,7 @@ namespace Upsilon.Parser Block = block; EndKeyword = endKeyword; - Span = new TextSpan(whileToken.Span.Start, endKeyword.Span.End); + Span = TextSpan.Between(whileToken.Span, endKeyword.Span); } public override SyntaxKind Kind => SyntaxKind.WhileStatement; diff --git a/Upsilon/Parser/SyntaxToken.cs b/Upsilon/Parser/SyntaxToken.cs index 0136799..9b37483 100644 --- a/Upsilon/Parser/SyntaxToken.cs +++ b/Upsilon/Parser/SyntaxToken.cs @@ -5,17 +5,17 @@ namespace Upsilon.Parser { public class SyntaxToken : SyntaxNode { - public SyntaxToken(SyntaxKind kind, int position, string text, object value) + public SyntaxToken(SyntaxKind kind, TextSpan position, string text, object value) { Kind = kind; - Span = new TextSpan(position, text.Length); + Span = position; Value = value; } - public SyntaxToken(SyntaxKind kind, int position, int length, object value) + public SyntaxToken(SyntaxKind kind, TextSpan position, int length, object value) { Kind = kind; - Span = new TextSpan(position, length); + Span = position; Value = value; } @@ -33,7 +33,7 @@ namespace Upsilon.Parser { public bool FollowedByLineBreak { get; } - public ReturnSyntaxToken(int position, bool followedByLineBreak) + public ReturnSyntaxToken(TextSpan position, bool followedByLineBreak) : base(SyntaxKind.ReturnKeyword, position, "return", null) { FollowedByLineBreak = followedByLineBreak; diff --git a/Upsilon/Text/SourceText.cs b/Upsilon/Text/SourceText.cs index f5e0a29..39cf7a7 100644 --- a/Upsilon/Text/SourceText.cs +++ b/Upsilon/Text/SourceText.cs @@ -1,109 +1,45 @@ using System; +using System.Text; namespace Upsilon.Text { public class SourceText { - private readonly string _text; - private readonly SourceTextLine[] _lines; + private readonly string[] _text; public SourceText(string text) { - _text = text; - if (string.IsNullOrEmpty(text)) - { - _lines = new SourceTextLine[0]; - return; - } - var lines = text.Split(new[] {Environment.NewLine}, StringSplitOptions.None); - _lines = new SourceTextLine[lines.Length]; - var linePos = 0; - for (var index = 0; index < lines.Length; index++) - { - var line = lines[index]; - _lines[index] = new SourceTextLine(linePos, line.Length + Environment.NewLine.Length); - linePos += line.Length + Environment.NewLine.Length; - } + _text = text.Split('\n'); } - public string GetSpan(int start, int length) + public string GetSpan(int startLine, int startPosition, int endLine, int endPosition) { - if (start < 0) + if (startPosition < 0) startPosition = 0; + if (startLine == endLine) { - length += start; - start = 0; - }; - if (start >= _text.Length) - return string.Empty; - if (start + length >= _text.Length) length = _text.Length - start; - return _text.Substring(start, length); - } - - public (int Line, int Pos) GetLinePosition(int spanPos) - { - var min = 0; - var max = _lines.Length - 1; - while (min <= max) + return _text[startLine].Substring(startPosition, endPosition - startPosition); + } + var sb = new StringBuilder(); + sb.Append(_text[startLine].Substring(startPosition)); + for (var i = startLine + 1; i < endLine; i++) { - var mid = (min + max) / 2 ; - if (mid >= _lines.Length) - { - max = _lines.Length - 1; - continue; - } - var midLine = _lines[mid]; - if (midLine.Start <= spanPos && midLine.End > spanPos) - { - var pos = spanPos - midLine.Start; - return (mid, pos); - } - if (spanPos >= midLine.End) - { - min = mid + 1; - } - else if (spanPos < midLine.Start) - { - max = mid - 1; - } + sb.Append(_text[i]); } - if (min >= _lines.Length) - { - min = _lines.Length - 1; - } - var newPos = spanPos - _lines[min].Start; - return (min, newPos); - } - - public int GetLineStartPos(int lineIndex) - { - return _lines[lineIndex].Start; - } - - public int GetLineCount() - { - return _lines.Length; - } - - public int GetTextLength() - { - return _text.Length; + if (endPosition > _text[endLine].Length) endPosition = _text[endLine].Length; + sb.Append(_text[endLine].Substring(0, endPosition)); + return sb.ToString(); } public string GetLine(int linePosition) { - var line = _lines[linePosition]; - return GetSpan(line.Start, line.LineLength); - } + return _text[linePosition]; - public SourceTextLine GetLineInfo(int lineIndex) - { - return _lines[lineIndex]; } public string GetSpan(TextSpan span) { - return GetSpan(span.Start, span.Length); + return GetSpan(span.StartLine, span.StartPosition, span.EndLine, span.EndPosition); } } } \ No newline at end of file diff --git a/Upsilon/Text/TextSpan.cs b/Upsilon/Text/TextSpan.cs index b2bf44f..968cb3e 100644 --- a/Upsilon/Text/TextSpan.cs +++ b/Upsilon/Text/TextSpan.cs @@ -2,19 +2,33 @@ namespace Upsilon.Text { public struct TextSpan { - public TextSpan(int start, int length) - { - Start = start; - Length = length; - } + public int StartLine { get; } + public int StartPosition { get; } + public int EndLine { get; } + public int EndPosition { get; } - public int Start { get; } - public int Length { get; } - public int End => Start + Length; + public TextSpan(int startLine, int startPosition, int endLine, int endPosition) + { + StartLine = startLine; + StartPosition = startPosition; + EndLine = endLine; + EndPosition = endPosition; + } public override string ToString() { - return $"{Start} - {End}"; + return $"({StartLine}, {StartPosition}) - ({EndLine}, {EndPosition})"; + } + + public static TextSpan Between(TextSpan start, TextSpan end) + { + return new TextSpan(start.StartLine, start.StartPosition, end.EndLine, end.EndPosition); + } + + public bool Contains(int linePosition, int characterPosition) + { + return StartLine >= linePosition && EndLine <= linePosition && characterPosition >= StartPosition && + characterPosition <= EndPosition; } } } \ No newline at end of file diff --git a/Upsilon/Utilities/SearchHelper.cs b/Upsilon/Utilities/SearchHelper.cs index 0602c00..ac9418c 100644 --- a/Upsilon/Utilities/SearchHelper.cs +++ b/Upsilon/Utilities/SearchHelper.cs @@ -7,9 +7,9 @@ namespace Upsilon.Utilities { public static class SearchHelper { - public static BoundScope GetScopeAt(this BoundScript script, int characterPosition) + public static BoundScope GetScopeAt(this BoundScript script, int linePosition, int characterPosition) { - foreach (var node in script.GetNodeAtPosition(characterPosition)) + foreach (var node in script.GetNodeAtPosition(linePosition, characterPosition)) { if (node is IBoundNodeScopeOwner scopeOwner && scopeOwner.Scope != null) { @@ -19,14 +19,14 @@ namespace Upsilon.Utilities return script.Scope; } - public static BoundNode GetBottomNodeAtPosition(this BoundNode node, int characterPosition) + public static BoundNode GetBottomNodeAtPosition(this BoundNode node, int linePosition, int characterPosition) { - return node.GetNodeAtPosition(characterPosition).First(); + return node.GetNodeAtPosition(linePosition, characterPosition).First(); } - - public static BoundStatement GetBottomStatementAtPosition(this BoundNode node, int characterPosition) + + public static BoundStatement GetBottomStatementAtPosition(this BoundNode node, int linePosition, int characterPosition) { - return (BoundStatement) node.GetNodeAtPosition(characterPosition).First(x => x is BoundStatement); + return (BoundStatement) node.GetNodeAtPosition(linePosition, characterPosition).First(x => x is BoundStatement); } public static Dictionary GetBoundScopeVisibleVariables(this BoundScope scope)