diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 607533e..c19a147 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -8,7 +8,7 @@ using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Binder { - internal class Binder + internal class Binder : IDisposable { private Diagnostics _diagnostics; public BoundScope Scope { get; private set; } @@ -29,6 +29,12 @@ namespace Upsilon.Binder return new Binder {_diagnostics = diagnostics, Scope = scope}; } + public void Dispose() + { + Scope?.Dispose(); + Scope = null; + _unboundFunctions.Clear(); + } public BoundScript BindScript(BlockStatementSyntax e) { @@ -45,7 +51,7 @@ namespace Upsilon.Binder Scope = Scope.ParentScope; } _unboundFunctions = new Dictionary(); - return new BoundScript((BoundBlockStatement) bound); + return new BoundScript((BoundBlockStatement) bound, e.Span); } private BoundStatement BindStatement(StatementSyntax s) @@ -74,7 +80,7 @@ namespace Upsilon.Binder return BindGenericForStatement((GenericForStatementSyntax) s); case SyntaxKind.BreakStatement: - return new BoundBreakStatement(); + return new BoundBreakStatement(s.Span); } throw new NotImplementedException(s.Kind.ToString()); @@ -124,7 +130,7 @@ namespace Upsilon.Binder return inExp; } - return new BoundUnaryExpression(op, inExp, op.OutType); + return new BoundUnaryExpression(op, inExp, op.OutType, e.Span); } private BoundExpression BindBinaryExpression(BinaryExpressionSyntax e) @@ -137,7 +143,7 @@ namespace Upsilon.Binder _diagnostics.LogUnknownBinaryOperator(e.Span, e.Operator.Kind, left.Type, right.Type); return left; } - return new BoundBinaryExpression(op, left, right, op.OutType); + return new BoundBinaryExpression(op, left, right, op.OutType, e.Span); } private BoundExpression BindLiteralExpression(LiteralExpressionSyntax e) @@ -166,7 +172,7 @@ namespace Upsilon.Binder _diagnostics.LogUnknownType(e.Span); break; } - return new BoundLiteralExpression(outValue); + return new BoundLiteralExpression(outValue, e.Span); } private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntax e) @@ -193,7 +199,7 @@ namespace Upsilon.Binder if (expression.Kind == BoundKind.VariableExpression) { var variableExpression =(BoundVariableExpression) expression; - var function = (FunctionVariableSymbol)variableExpression.Variable; + var function = (FunctionVariableSymbol)variableExpression.Variable.VariableSymbol; if (!function.IsBound) { Scope = new BoundScope(Scope); @@ -215,7 +221,7 @@ namespace Upsilon.Binder } //TODO: validate parameters - return new BoundFunctionCallExpression(expression, parameters.ToImmutable()); + return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span); } private BoundExpression BindVariableExpression(VariableExpressionSyntax e) @@ -224,16 +230,16 @@ namespace Upsilon.Binder if (!Scope.TryGetVariable(name, true, out var variable)) { _diagnostics.LogUnknownVariable(e.Identifier.Span, name); - return new BoundLiteralExpression(new ScriptNull()); + return new BoundLiteralExpression(new ScriptNull(), e.Span); } - - return new BoundVariableExpression(variable); + var boundVariable = new BoundVariableSymbol(variable, e.Identifier.Span); + return new BoundVariableExpression(boundVariable, e.Span); } private BoundStatement BindExpressionStatement(ExpressionStatementSyntax s) { var exp = BindExpression(s.Expression); - return new BoundExpressionStatement(exp); + return new BoundExpressionStatement(exp, s.Span); } private VariableSymbol TryBindVariable(string name, bool isLocal, BoundExpression assignment) @@ -272,7 +278,7 @@ namespace Upsilon.Binder } else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v) { - v.Variable.Type = variable.Type; + v.Variable.VariableSymbol.Type = variable.Type; } else if (assignment.Type == Type.Unknown) { @@ -299,12 +305,13 @@ namespace Upsilon.Binder var boundVariable = TryBindVariable(name, isLocal, boundExpression); if (boundVariable != null) { - return new BoundVariableAssignment(boundVariable, boundExpression, isLocal); + var variable = new BoundVariableSymbol(boundVariable, variableExpression.Span); + return new BoundVariableAssignment(variable, boundExpression, isLocal, e.Span); } } - return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull())); + return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull(), e.Span), e.Span); } private BoundStatement BindMultiAssignmentStatement(MultiAssignmentStatementSyntax s) @@ -318,7 +325,7 @@ namespace Upsilon.Binder var boundVariable = TryBindVariable(identifierToken.Name, isLocal, assignment); ls.Add(boundVariable); } - return new BoundMultiAssignmentStatement(ls.ToImmutableArray(), assignment); + return new BoundMultiAssignmentStatement(ls.ToImmutableArray(), assignment, s.Span); } private BoundStatement BindBlockStatement(BlockStatementSyntax e) @@ -330,7 +337,7 @@ namespace Upsilon.Binder arr.Add(bound); } - return new BoundBlockStatement(arr.ToImmutable()); + return new BoundBlockStatement(arr.ToImmutable(), e.Span); } private BoundStatement BindIfStatement(IfStatementSyntax e) @@ -343,21 +350,21 @@ namespace Upsilon.Binder { var nextElseIf = BindIfStatement(e.NextElseIfStatement); return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block, - (BoundIfStatement) nextElseIf); + (BoundIfStatement) nextElseIf, e.Span); } if (e.ElseStatement == null) { - return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block); + return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block, e.Span); } else { Scope = new BoundScope(Scope); var elseBlock = BindBlockStatement(e.ElseStatement.Block); - var elseStatement = new BoundElseStatement((BoundBlockStatement) elseBlock); + var elseStatement = new BoundElseStatement((BoundBlockStatement) elseBlock, e.Span); Scope = Scope.ParentScope; return new BoundIfStatement((BoundExpressionStatement) condition, (BoundBlockStatement) block, - elseStatement); + elseStatement, e.Span); } } @@ -377,12 +384,12 @@ namespace Upsilon.Binder Scope = innerScope; var block = BindBlockStatement(e.Block); Scope = Scope.ParentScope; - var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block); + var func = new BoundFunctionExpression(parameters.ToImmutable(), (BoundBlockStatement) block, e.Span); return func; } else { - var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block); + var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span); if (variableSymbol == null) { _unboundFunctions.Add( Guid.NewGuid().ToString(), unbound); @@ -433,18 +440,18 @@ namespace Upsilon.Binder else { _diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span); - return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull())); + return new BoundExpressionStatement(new BoundLiteralExpression(new ScriptNull(), e.Span), e.Span); } } } - return new BoundFunctionAssignmentStatement(variable, func); + return new BoundFunctionAssignmentStatement(variable, func, e.Span); } private BoundStatement BindReturnStatement(ReturnStatementSyntax e) { var expression = BindExpression(e.Expression); - return new BoundReturnStatement(expression); + return new BoundReturnStatement(expression, e.Span); } private BoundExpression BindTableExpression(TableExpressionSyntax e) @@ -466,7 +473,7 @@ namespace Upsilon.Binder dictionary.Add(variable.Key, true); } Scope = s; - return new BoundTableExpression(keyType, valueType, dictionary, statements); + return new BoundTableExpression(keyType, valueType, dictionary, statements.ToImmutable(), e.Span); } private BoundExpression BindIndexExpression(IndexExpressionSyntax e) @@ -477,19 +484,19 @@ namespace Upsilon.Binder if (index.Type != Type.Number && index.Type != Type.String && index.Type != Type.Unknown) { _diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span); - return new BoundLiteralExpression(new ScriptNull()); + return new BoundLiteralExpression(new ScriptNull(), e.Span); } switch (expression.Type) { case Type.Table: case Type.UserData: case Type.Unknown: - return new BoundIndexExpression(expression, index, Type.Unknown); + return new BoundIndexExpression(expression, index, Type.Unknown, e.Span); case Type.String when index.Type == Type.Number: - return new BoundIndexExpression(expression, index, Type.String); + return new BoundIndexExpression(expression, index, Type.String, e.Span); default: _diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span); - return new BoundLiteralExpression(new ScriptNull()); + return new BoundLiteralExpression(new ScriptNull(), e.Span); } } @@ -502,12 +509,12 @@ namespace Upsilon.Binder case Type.Table: case Type.UserData: case Type.Unknown: - return new BoundFullStopIndexExpression(expression, index); + return new BoundFullStopIndexExpression(expression, index, e.Span); case Type.String: - return new BoundFullStopIndexExpression(expression, index); + return new BoundFullStopIndexExpression(expression, index, e.Span); default: _diagnostics.LogInvalidIndexExpression(expression.Type, Type.String, e.Span); - return new BoundLiteralExpression(new ScriptNull()); + return new BoundLiteralExpression(new ScriptNull(), e.Span); } } @@ -520,7 +527,7 @@ namespace Upsilon.Binder indexableExpression = (BoundFullStopIndexExpression)BindExpression(e.TableExpression); var value = BindExpression(e.Expression); - return new BoundTableAssigmentStatement(indexableExpression, value); + return new BoundTableAssigmentStatement(indexableExpression, value, e.Span); } private BoundStatement BindNumericForStatement(NumericForStatementSyntax e) @@ -536,7 +543,8 @@ namespace Upsilon.Binder boundStep = BindExpression(e.StepExpression); var block = BindBlockStatement((BlockStatementSyntax) e.Block); Scope = Scope.ParentScope; - return new BoundNumericForStatement(variable, boundStart, boundStop, boundStep, (BoundBlockStatement) block); + return new BoundNumericForStatement(variable, boundStart, boundStop, boundStep, (BoundBlockStatement) block, + e.Span); } private BoundStatement BindGenericForStatement(GenericForStatementSyntax e) @@ -552,7 +560,7 @@ namespace Upsilon.Binder var boundEnumerableExpression = BindExpression(e.EnumerableExpression); var block = BindBlockStatement(e.Block); - return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block); + return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block, e.Span); } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs b/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs index 143faa6..00035d1 100644 --- a/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundBinaryExpression.cs @@ -1,11 +1,12 @@ using Upsilon.BaseTypes; -using Upsilon.Parser; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundBinaryExpression : BoundExpression { - public BoundBinaryExpression(BoundBinaryOperator op, BoundExpression leftExpression, BoundExpression rightExpression, Type type) + public BoundBinaryExpression(BoundBinaryOperator op, BoundExpression leftExpression, + BoundExpression rightExpression, Type type, TextSpan span) : base(span) { Operator = op; LeftExpression = leftExpression; @@ -14,6 +15,16 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundBinaryExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= LeftExpression.Span.Start && characterPosition <= LeftExpression.Span.End) + return LeftExpression.GetNodeAtPosition(characterPosition); + if (characterPosition >= RightExpression.Span.Start && characterPosition <= RightExpression.Span.End) + return RightExpression.GetNodeAtPosition(characterPosition); + return this; + + } + public override Type Type { get; } public BoundBinaryOperator Operator { get; } diff --git a/Upsilon/Binder/BoundExpressions/BoundExpression.cs b/Upsilon/Binder/BoundExpressions/BoundExpression.cs index 31f8f40..1fc0bde 100644 --- a/Upsilon/Binder/BoundExpressions/BoundExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundExpression.cs @@ -1,9 +1,14 @@ using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { public abstract class BoundExpression : BoundNode { + protected BoundExpression(TextSpan span) : base(span) + { + } + public abstract Type Type { get; } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs index b3f9824..d155418 100644 --- a/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundFunctionCallExpression.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { @@ -8,13 +9,27 @@ namespace Upsilon.Binder public BoundExpression Identifier { get; } public ImmutableArray Parameters { get; } - public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray parameters) + public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray parameters, + TextSpan span) : base(span) { Identifier = identifier; Parameters = parameters; } public override BoundKind Kind => BoundKind.BoundFunctionCallExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Identifier.Span.Start && characterPosition <= Identifier.Span.End) + return Identifier.GetNodeAtPosition(characterPosition); + foreach (var parameter in Parameters) + { + if (characterPosition >= parameter.Span.Start && characterPosition <= parameter.Span.End) + return parameter.GetNodeAtPosition(characterPosition); + } + return this; + + } + public override Type Type => Type.Unknown; } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundFunctionExpression.cs b/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs similarity index 55% rename from Upsilon/Binder/BoundStatements/BoundFunctionExpression.cs rename to Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs index 6615923..68f3e58 100644 --- a/Upsilon/Binder/BoundStatements/BoundFunctionExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundFunctionExpression.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { @@ -8,27 +9,20 @@ namespace Upsilon.Binder public ImmutableArray Parameters { get; } public BoundBlockStatement Block { get; set; } - public BoundFunctionExpression(ImmutableArray parameters, BoundBlockStatement block) + public BoundFunctionExpression(ImmutableArray parameters, BoundBlockStatement block, TextSpan span) : base(span) { Parameters = parameters; Block = block; } public override BoundKind Kind => BoundKind.BoundFunctionExpression; - public override Type Type => Type.Function; - } - - public class BoundFunctionAssignmentStatement : BoundStatement - { - public VariableSymbol Variable { get; } - public BoundFunctionExpression Func { get; } - - public BoundFunctionAssignmentStatement(VariableSymbol variable, BoundFunctionExpression func) + public override BoundNode GetNodeAtPosition(int characterPosition) { - Variable = variable; - Func = func; + if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + return Block.GetNodeAtPosition(characterPosition); + return this; } - public override BoundKind Kind => BoundKind.BoundFunctionAssignmentStatement; + public override Type Type => Type.Function; } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs index 7c1b6a9..99792bb 100644 --- a/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundIndexExpression.cs @@ -1,11 +1,12 @@ using Upsilon.BaseTypes; using Upsilon.Parser; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundIndexExpression : BoundExpression { - public BoundIndexExpression(BoundExpression identifier, BoundExpression index, Type type) + public BoundIndexExpression(BoundExpression identifier, BoundExpression index, Type type, TextSpan span) : base(span) { Identifier = identifier; Index = index; @@ -16,6 +17,16 @@ namespace Upsilon.Binder public BoundExpression Index { get; } public override BoundKind Kind => BoundKind.BoundIndexExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Identifier.Span.Start && characterPosition <= Identifier.Span.End) + return Identifier.GetNodeAtPosition(characterPosition); + if (characterPosition >= Index.Span.Start && characterPosition <= Index.Span.End) + return Index.GetNodeAtPosition(characterPosition); + return this; + + } + public override Type Type { get; } } @@ -24,13 +35,20 @@ namespace Upsilon.Binder public BoundExpression Expression { get; } public string Index { get; } - public BoundFullStopIndexExpression(BoundExpression expression, string index) + public BoundFullStopIndexExpression(BoundExpression expression, string index, TextSpan span) : base(span) { Expression = expression; Index = index; } public override BoundKind Kind => BoundKind.BoundFullstopIndexExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Expression.Span.Start && characterPosition <= Expression.Span.End) + return Expression.GetNodeAtPosition(characterPosition); + return this; + } + public override Type Type => Type.Unknown; } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs b/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs index 0e78ec5..d9adedc 100644 --- a/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundLiteralExpression.cs @@ -1,15 +1,21 @@ using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { internal class BoundLiteralExpression : BoundExpression { - public BoundLiteralExpression(ScriptType value) + public BoundLiteralExpression(ScriptType value, TextSpan span) : base(span) { Value = value; } public override BoundKind Kind => BoundKind.BoundLiteralExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + return this; + } + public override Type Type => Value.Type; public ScriptType Value { get; } } diff --git a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs index b24c3ba..5c0f270 100644 --- a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using System.Collections.Immutable; using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundTableExpression : BoundExpression { public BoundTableExpression(Type keyType, Type valueType, Dictionary expressions, - ImmutableArray.Builder statements) + ImmutableArray statements, TextSpan span) : base(span) { KeyType = keyType; ValueType = valueType; @@ -16,12 +17,23 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundTableExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + foreach (var statement in Statements) + { + if (characterPosition >= statement.Span.Start && characterPosition <= statement.Span.End) + return statement.GetNodeAtPosition(characterPosition); + } + return this; + + } + public override Type Type => Type.Table; public Type KeyType { get; } public Type ValueType { get; } public Dictionary Expressions { get; } - public ImmutableArray.Builder Statements { get; } + public ImmutableArray Statements { get; } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs b/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs index 77d9555..3cbdfb0 100644 --- a/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundUnaryExpression.cs @@ -1,13 +1,21 @@ using Upsilon.BaseTypes; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundUnaryExpression : BoundExpression { public override BoundKind Kind => BoundKind.BoundUnaryExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= InExpression.Span.Start && characterPosition <= InExpression.Span.End) + return InExpression.GetNodeAtPosition(characterPosition); + return this; + } + public override Type Type { get; } - public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type) + public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type, TextSpan span) : base(span) { Operator = op; InExpression = inExpression; diff --git a/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs index 99b2575..6fb4602 100644 --- a/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs +++ b/Upsilon/Binder/BoundExpressions/BoundVariableExpression.cs @@ -1,17 +1,23 @@ using System; +using Upsilon.Text; using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Binder { public class BoundVariableExpression : BoundExpression { - public BoundVariableExpression(VariableSymbol variable) + public BoundVariableExpression(BoundVariableSymbol variable, TextSpan span) : base(span) { Variable = variable; } - public VariableSymbol Variable { get; } + public BoundVariableSymbol Variable { get; } public override BoundKind Kind => BoundKind.VariableExpression; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + return Variable; + } + public override Type Type => Variable.Type; } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs b/Upsilon/Binder/BoundExpressions/UnboundFunctionExpression.cs similarity index 79% rename from Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs rename to Upsilon/Binder/BoundExpressions/UnboundFunctionExpression.cs index 89ee80b..98d5e50 100644 --- a/Upsilon/Binder/BoundStatements/UnboundFunctionExpression.cs +++ b/Upsilon/Binder/BoundExpressions/UnboundFunctionExpression.cs @@ -1,12 +1,13 @@ using System.Collections.Immutable; using Upsilon.Parser; +using Upsilon.Text; namespace Upsilon.Binder { public class UnboundFunctionExpression : BoundFunctionExpression { public UnboundFunctionExpression(ImmutableArray parameters, - BlockStatementSyntax unboundBlock) : base(parameters, null) + BlockStatementSyntax unboundBlock, TextSpan span) : base(parameters, null, span) { UnboundBlock = unboundBlock; } diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index 60f0e84..4b0c16c 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -2,6 +2,7 @@ namespace Upsilon.Binder { public enum BoundKind { + BoundVariableSymbol, BoundScript, BoundLiteralExpression, @@ -28,5 +29,6 @@ namespace Upsilon.Binder BoundNumericForStatement, BoundGenericForStatement, BoundBreakStatement, + } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundNode.cs b/Upsilon/Binder/BoundNode.cs index 40ddcfa..2563f34 100644 --- a/Upsilon/Binder/BoundNode.cs +++ b/Upsilon/Binder/BoundNode.cs @@ -4,7 +4,14 @@ namespace Upsilon.Binder { public abstract class BoundNode { + protected BoundNode(TextSpan span) + { + Span = span; + } + public abstract BoundKind Kind { get; } - public TextSpan Span { get; protected set; } + public TextSpan Span { get; } + + public abstract BoundNode GetNodeAtPosition(int characterPosition); } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundScope.cs b/Upsilon/Binder/BoundScope.cs index ee7581f..411c81f 100644 --- a/Upsilon/Binder/BoundScope.cs +++ b/Upsilon/Binder/BoundScope.cs @@ -1,14 +1,14 @@ +using System; using System.Collections.Generic; namespace Upsilon.Binder { - public class BoundScope + public class BoundScope : IDisposable { public readonly BoundScope ParentScope; private BoundScope _readOnlyScope; public readonly Dictionary Variables; - public BoundScope(BoundScope parentScope) { ParentScope = parentScope; @@ -26,6 +26,11 @@ namespace Upsilon.Binder return scope; } + public void Dispose() + { + Variables.Clear(); + } + public void DefineLocalVariable(VariableSymbol var) { Variables.Add(var.Name, var); diff --git a/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs b/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs index beecbbb..c13d3f6 100644 --- a/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundBlockStatement.cs @@ -1,15 +1,26 @@ using System.Collections.Immutable; +using System.Linq; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundBlockStatement : BoundStatement { - public BoundBlockStatement(ImmutableArray statements) + public BoundBlockStatement(ImmutableArray statements, TextSpan span) : base(span) { Statements = statements; } public override BoundKind Kind => BoundKind.BoundBlockStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + foreach (var statement in Statements) + { + if (characterPosition >= statement.Span.Start && characterPosition <= statement.Span.End) + return statement.GetNodeAtPosition(characterPosition); + } + return this; + } public ImmutableArray Statements { get; } } diff --git a/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs b/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs index 8a8872b..157f0fb 100644 --- a/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundBreakStatement.cs @@ -1,7 +1,19 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundBreakStatement : BoundStatement { + public BoundBreakStatement(TextSpan span) : base(span) + { + } + public override BoundKind Kind => BoundKind.BoundBreakStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Span.Start && characterPosition <= Span.End) + return this; + return null; + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs b/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs index c4ac943..4eb1035 100644 --- a/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundExpressionStatement.cs @@ -1,11 +1,19 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundExpressionStatement : BoundStatement { public BoundExpression Expression { get; } public override BoundKind Kind => BoundKind.BoundExpressionStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Span.Start && characterPosition <= Span.End) + return Expression.GetNodeAtPosition(characterPosition); + return null; + } - public BoundExpressionStatement(BoundExpression expression) + public BoundExpressionStatement(BoundExpression expression, TextSpan span):base(span) { Expression = expression; } diff --git a/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs new file mode 100644 index 0000000..26613fe --- /dev/null +++ b/Upsilon/Binder/BoundStatements/BoundFunctionAssignmentStatement.cs @@ -0,0 +1,24 @@ +using Upsilon.Text; + +namespace Upsilon.Binder +{ + public class BoundFunctionAssignmentStatement : BoundStatement + { + public VariableSymbol Variable { get; } + public BoundFunctionExpression Func { get; } + + public BoundFunctionAssignmentStatement(VariableSymbol variable, BoundFunctionExpression func, TextSpan span): base(span) + { + Variable = variable; + Func = func; + } + + public override BoundKind Kind => BoundKind.BoundFunctionAssignmentStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Func.Span.Start && characterPosition <= Func.Span.End) + return Func.GetNodeAtPosition(characterPosition); + return this; + } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs b/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs index 0116dd9..a855a37 100644 --- a/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundGenericForStatement.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using Upsilon.Text; namespace Upsilon.Binder { @@ -9,7 +10,7 @@ namespace Upsilon.Binder public BoundStatement Block { get; } public BoundGenericForStatement(ImmutableArray variables, - BoundExpression boundEnumerableExpression, BoundStatement block) + BoundExpression boundEnumerableExpression, BoundStatement block, TextSpan span) : base(span) { Variables = variables; BoundEnumerableExpression = boundEnumerableExpression; @@ -17,5 +18,13 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundGenericForStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= BoundEnumerableExpression.Span.Start && characterPosition <= BoundEnumerableExpression.Span.End) + return BoundEnumerableExpression.GetNodeAtPosition(characterPosition); + if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + return Block.GetNodeAtPosition(characterPosition); + return this; + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundIfStatement.cs b/Upsilon/Binder/BoundStatements/BoundIfStatement.cs index 1a80bfd..774b152 100644 --- a/Upsilon/Binder/BoundStatements/BoundIfStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundIfStatement.cs @@ -1,20 +1,22 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundIfStatement : BoundStatement { - public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block) + public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, TextSpan span): base(span) { Condition = condition; Block = block; } - public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundElseStatement elseStatement) + public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundElseStatement elseStatement, TextSpan span) : base(span) { Condition = condition; Block = block; ElseStatement = elseStatement; } - public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundIfStatement nextElseIf) + public BoundIfStatement(BoundExpressionStatement condition, BoundBlockStatement block, BoundIfStatement nextElseIf, TextSpan span) : base(span) { Condition = condition; Block = block; @@ -22,6 +24,18 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundIfStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Condition.Span.Start && characterPosition <= Condition.Span.End) + return Condition.GetNodeAtPosition(characterPosition); + if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + return Block.GetNodeAtPosition(characterPosition); + if (NextElseIf != null && characterPosition >= NextElseIf.Span.Start && characterPosition <= NextElseIf.Span.End) + return NextElseIf.GetNodeAtPosition(characterPosition); + if (ElseStatement != null && characterPosition >= ElseStatement.Span.Start && characterPosition <= ElseStatement.Span.End) + return ElseStatement.GetNodeAtPosition(characterPosition); + return this; + } public BoundExpressionStatement Condition { get; } public BoundBlockStatement Block { get; } @@ -33,11 +47,17 @@ namespace Upsilon.Binder { public BoundBlockStatement Block { get; } - public BoundElseStatement(BoundBlockStatement block) + public BoundElseStatement(BoundBlockStatement block, TextSpan span) : base(span) { Block = block; } public override BoundKind Kind => BoundKind.BoundElseStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (Block != null && characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + return Block.GetNodeAtPosition(characterPosition); + return this; + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs index 04984c3..1fe1ec6 100644 --- a/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundMultiAssignmentStatement.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Upsilon.Text; namespace Upsilon.Binder { @@ -8,12 +9,20 @@ namespace Upsilon.Binder public ImmutableArray Variables { get; } public BoundExpression Assignment { get; } - public BoundMultiAssignmentStatement(ImmutableArray variables, BoundExpression assignment) + public BoundMultiAssignmentStatement(ImmutableArray variables, BoundExpression assignment, + TextSpan span) : base(span) { Variables = variables; Assignment = assignment; } public override BoundKind Kind => BoundKind.BoundMultiAssignmentStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Assignment.Span.Start && characterPosition <= Assignment.Span.End) + return Assignment.GetNodeAtPosition(characterPosition); + return this; + + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs b/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs index 0220c3b..41c59e1 100644 --- a/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundNumericForStatement.cs @@ -1,3 +1,5 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundNumericForStatement : BoundStatement @@ -9,7 +11,7 @@ namespace Upsilon.Binder public BoundBlockStatement Block { get; } public BoundNumericForStatement(VariableSymbol variable, BoundExpression boundStart, - BoundExpression boundStop, BoundExpression boundStep, BoundBlockStatement block) + BoundExpression boundStop, BoundExpression boundStep, BoundBlockStatement block, TextSpan span) : base(span) { Variable = variable; BoundStart = boundStart; @@ -19,5 +21,18 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundNumericForStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= BoundStart.Span.Start && characterPosition <= BoundStart.Span.End) + return BoundStart.GetNodeAtPosition(characterPosition); + if (characterPosition >= BoundStop.Span.Start && characterPosition <= BoundStop.Span.End) + return BoundStop.GetNodeAtPosition(characterPosition); + if (characterPosition >= BoundStep.Span.Start && characterPosition <= BoundStep.Span.End) + return BoundStep.GetNodeAtPosition(characterPosition); + if (characterPosition >= Block.Span.Start && characterPosition <= Block.Span.End) + return Block.GetNodeAtPosition(characterPosition); + return this; + + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs b/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs index a34b563..6df0552 100644 --- a/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundReturnStatement.cs @@ -1,13 +1,21 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundReturnStatement : BoundStatement { - public BoundReturnStatement(BoundExpression expression) + public BoundReturnStatement(BoundExpression expression, TextSpan span) : base(span) { Expression = expression; } public BoundExpression Expression { get; } public override BoundKind Kind => BoundKind.BoundReturnStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Expression.Span.Start && characterPosition <= Expression.Span.End) + return Expression.GetNodeAtPosition(characterPosition); + return this; + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundScript.cs b/Upsilon/Binder/BoundStatements/BoundScript.cs index ecb3e81..74a541a 100644 --- a/Upsilon/Binder/BoundStatements/BoundScript.cs +++ b/Upsilon/Binder/BoundStatements/BoundScript.cs @@ -1,15 +1,20 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Binder { public class BoundScript : BoundStatement { - public BoundScript(BoundBlockStatement statement) + public BoundScript(BoundBlockStatement statement, TextSpan span) : base(span) { Statement = statement; } public override BoundKind Kind => BoundKind.BoundScript; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + return Statement.GetNodeAtPosition(characterPosition); + } public BoundBlockStatement Statement { get; } } diff --git a/Upsilon/Binder/BoundStatements/BoundStatement.cs b/Upsilon/Binder/BoundStatements/BoundStatement.cs index 4f2b707..9977728 100644 --- a/Upsilon/Binder/BoundStatements/BoundStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundStatement.cs @@ -1,6 +1,11 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public abstract class BoundStatement : BoundNode { + protected BoundStatement(TextSpan span) : base(span) + { + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs index a578afa..f307965 100644 --- a/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundTableAssigmentStatement.cs @@ -1,3 +1,5 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundTableAssigmentStatement : BoundStatement @@ -5,12 +7,22 @@ namespace Upsilon.Binder public BoundExpression TableIndexExpression { get; } public BoundExpression Value { get; } - public BoundTableAssigmentStatement(BoundExpression tableIndexExpression, BoundExpression value) + public BoundTableAssigmentStatement(BoundExpression tableIndexExpression, BoundExpression value, + TextSpan span) : base(span) { TableIndexExpression = tableIndexExpression; Value = value; } public override BoundKind Kind => BoundKind.BoundTableAssigmentStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= TableIndexExpression.Span.Start && characterPosition <= TableIndexExpression.Span.End) + return TableIndexExpression.GetNodeAtPosition(characterPosition); + if (characterPosition >= Value.Span.Start && characterPosition <= Value.Span.End) + return Value.GetNodeAtPosition(characterPosition); + return this; + + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs b/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs index d72840c..2d75d34 100644 --- a/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs +++ b/Upsilon/Binder/BoundStatements/BoundVariableAssignment.cs @@ -1,12 +1,15 @@ +using Upsilon.Text; + namespace Upsilon.Binder { public class BoundVariableAssignment : BoundStatement { - public VariableSymbol Variable { get; } + public BoundVariableSymbol Variable { get; } public BoundExpression BoundExpression { get; } public bool IsLocalDefinition { get; } - public BoundVariableAssignment(VariableSymbol variable, BoundExpression boundExpression, bool isLocalDefinition) + public BoundVariableAssignment(BoundVariableSymbol variable, BoundExpression boundExpression, bool isLocalDefinition, + TextSpan span) : base(span) { Variable = variable; BoundExpression = boundExpression; @@ -14,5 +17,14 @@ namespace Upsilon.Binder } public override BoundKind Kind => BoundKind.BoundAssignmentStatement; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + if (characterPosition >= Variable.Span.Start && characterPosition <= Variable.Span.End) + return Variable; + if (characterPosition >= BoundExpression.Span.Start && characterPosition <= BoundExpression.Span.End) + return BoundExpression.GetNodeAtPosition(characterPosition); + return this; + + } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundVariableSymbol.cs b/Upsilon/Binder/BoundVariableSymbol.cs new file mode 100644 index 0000000..f13e970 --- /dev/null +++ b/Upsilon/Binder/BoundVariableSymbol.cs @@ -0,0 +1,23 @@ +using Upsilon.BaseTypes; +using Upsilon.Text; + +namespace Upsilon.Binder +{ + public class BoundVariableSymbol : BoundExpression + { + public BoundVariableSymbol(VariableSymbol variableSymbol, TextSpan span) : base(span) + { + VariableSymbol = variableSymbol; + Type = variableSymbol.Type; + } + + public VariableSymbol VariableSymbol { get; } + public override BoundKind Kind => BoundKind.BoundVariableSymbol; + public override BoundNode GetNodeAtPosition(int characterPosition) + { + return this; + } + + public override Type Type { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Diagnostics.cs b/Upsilon/Diagnostics.cs index fd2674b..100e6a1 100644 --- a/Upsilon/Diagnostics.cs +++ b/Upsilon/Diagnostics.cs @@ -90,6 +90,17 @@ 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); diff --git a/Upsilon/Evaluator/EvaluationScope.cs b/Upsilon/Evaluator/EvaluationScope.cs index 4bcb508..4f73d27 100644 --- a/Upsilon/Evaluator/EvaluationScope.cs +++ b/Upsilon/Evaluator/EvaluationScope.cs @@ -1,12 +1,13 @@ +using System; using System.Collections.Generic; using Upsilon.BaseTypes; using Upsilon.Binder; namespace Upsilon.Evaluator { - public class EvaluationScope + public class EvaluationScope : IDisposable { - private readonly EvaluationScope _parentScope; + private EvaluationScope _parentScope; private EvaluationScope _getOnlyParentScope; public readonly Dictionary Variables; @@ -29,6 +30,13 @@ namespace Upsilon.Evaluator return scope; } + public void Dispose() + { + _parentScope?.Dispose(); + _parentScope = null; + Variables.Clear(); + } + public void AssignToNearest(VariableSymbol symbol, ScriptType value) { if (Variables.ContainsKey(symbol.Name)) diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 6a56f4f..10ca704 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -10,7 +10,7 @@ using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Evaluator { - internal class Evaluator + internal class Evaluator : IDisposable { private Diagnostics _diagnostics; private ScriptType _lastValue; @@ -38,6 +38,13 @@ namespace Upsilon.Evaluator return new Evaluator {_diagnostics = diagnostics, Scope = scope}; } + public void Dispose() + { + Scope.Dispose(); + _lastValue = null; + _returnValue = null; + } + public ScriptType Evaluate(BoundScript e) { EvaluateNode(e.Statement); @@ -302,11 +309,11 @@ namespace Upsilon.Evaluator var val = EvaluateExpression(e.BoundExpression); if (e.IsLocalDefinition) { - Scope.CreateLocal(e.Variable, val); + Scope.CreateLocal(e.Variable.VariableSymbol, val); } else { - Scope.AssignToNearest(e.Variable, val); + Scope.AssignToNearest(e.Variable.VariableSymbol, val); } _lastValue = val; } @@ -339,11 +346,11 @@ namespace Upsilon.Evaluator private ScriptType EvaluateVariableExpression(BoundVariableExpression e) { - if (Scope.TryGet(e.Variable, out var val)) + if (Scope.TryGet(e.Variable.VariableSymbol, out var val)) { return val; } - throw new Exception($"Cannot find variable: '{e.Variable.Name}'"); + throw new Exception($"Cannot find variable: '{e.Variable.VariableSymbol.Name}'"); } private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement) diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 61b61c6..9d6b5a8 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -10,11 +10,11 @@ using Upsilon.Utilities; namespace Upsilon.Evaluator { - public class Script + public class Script : IDisposable { - private SourceText ScriptString { get; } + public SourceText ScriptString { get; } private Evaluator Evaluator { get; } - private readonly BlockStatementSyntax _parsed; + private BlockStatementSyntax _parsed; private BoundScript _bound; public Diagnostics Diagnostics { get; } private Binder.Binder Binder { get; } @@ -128,5 +128,14 @@ namespace Upsilon.Evaluator { return _parsed.Print(); } + + public void Dispose() + { + Binder?.Dispose(); + Evaluator?.Dispose(); + Scope?.Dispose(); + _parsed = null; + _bound = null; + } } } \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs index 733815a..81fc2a1 100644 --- a/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/FunctionCallExpressionSyntax.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Upsilon.Text; namespace Upsilon.Parser { @@ -17,6 +18,7 @@ namespace Upsilon.Parser OpenParenthesis = openParenthesis; Parameters = parameters; CloseParenthesis = closeParenthesis; + Span = new TextSpan(Identifier.Span.Start, CloseParenthesis.Span.End - Identifier.Span.End); } public override SyntaxKind Kind => SyntaxKind.FunctionCallExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs index 5a4ca0f..52ecf3a 100644 --- a/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/FunctionExpressionSyntax.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Upsilon.Text; namespace Upsilon.Parser { @@ -22,6 +23,7 @@ namespace Upsilon.Parser CloseParenthesis = closeParenthesis; Block = block; EndToken = endToken; + Span = new TextSpan(FunctionToken.Span.Start, EndToken.Span.End - FunctionToken.Span.Start); } public override SyntaxKind Kind => SyntaxKind.FunctionExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs index f429461..6b460a7 100644 --- a/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/IndexExpressionSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -16,6 +17,7 @@ namespace Upsilon.Parser OpenBracket = openBracket; Index = index; CloseBracket = closeBracket; + Span = new TextSpan(expression.Span.Start, CloseBracket.Span.End - expression.Span.Start); } public override SyntaxKind Kind => SyntaxKind.IndexExpression; @@ -39,6 +41,7 @@ namespace Upsilon.Parser Expression = expression; FullStop = fullStop; Index = index; + Span = new TextSpan(expression.Span.Start, Index.Span.End - expression.Span.Start); } public override SyntaxKind Kind => SyntaxKind.FullStopIndexExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs index a95eff1..c679bfe 100644 --- a/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/ParenthesizedExpressionSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -9,6 +10,7 @@ namespace Upsilon.Parser OpenParenthesis = openParenthesis; Expression = expression; CloseParenthesis = closeParenthesis; + Span = new TextSpan(OpenParenthesis.Span.Start, CloseParenthesis.Span.End - OpenParenthesis.Span.Start); } public override SyntaxKind Kind => SyntaxKind.ParenthesizedExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs index 4ac84d9..098fdbc 100644 --- a/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/UnaryExpressionSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -8,6 +9,7 @@ namespace Upsilon.Parser { Operator = @operator; Expression = expression; + Span = new TextSpan(Operator.Span.Start, expression.Span.End - Operator.Span.Start); } public override SyntaxKind Kind => SyntaxKind.UnaryExpression; diff --git a/Upsilon/Parser/ExpressionSyntax/VariableExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/VariableExpressionSyntax.cs index 2e1e401..504cfc7 100644 --- a/Upsilon/Parser/ExpressionSyntax/VariableExpressionSyntax.cs +++ b/Upsilon/Parser/ExpressionSyntax/VariableExpressionSyntax.cs @@ -9,6 +9,7 @@ namespace Upsilon.Parser public VariableExpressionSyntax(IdentifierToken identifier) { Identifier = identifier; + Span = Identifier.Span; } public override SyntaxKind Kind => SyntaxKind.VariableExpression; diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 88324de..8329115 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -218,13 +218,13 @@ namespace Upsilon.Parser localToken = NextToken(); } var functionToken = MatchToken(SyntaxKind.FunctionKeyword); - var identifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier); + var identifier = MatchToken(SyntaxKind.Identifier); var openParenthesis = MatchToken(SyntaxKind.OpenParenthesis); var variableBuilder = ImmutableArray.CreateBuilder(); - while (Current.Kind != SyntaxKind.CloseParenthesis) + while (Current.Kind != SyntaxKind.CloseParenthesis || Current.Kind == SyntaxKind.EndOfFile) { - var variableIdentifier = (IdentifierToken)MatchToken(SyntaxKind.Identifier); - variableBuilder.Add(variableIdentifier); + var variableIdentifier = MatchToken(SyntaxKind.Identifier); + variableBuilder.Add((IdentifierToken) variableIdentifier); if (Current.Kind == SyntaxKind.Comma) NextToken(); } @@ -233,7 +233,7 @@ namespace Upsilon.Parser var endToken = MatchToken(SyntaxKind.EndKeyword); var functionExpression = new FunctionExpressionSyntax(functionToken, openParenthesis, variableBuilder.ToImmutable(), closeParenthesis, (BlockStatementSyntax) block, endToken); - return new FunctionAssignmentStatementSyntax(localToken, identifier, functionExpression); + return new FunctionAssignmentStatementSyntax(localToken, (IdentifierToken) identifier, functionExpression); } private StatementSyntax ParseExpressionStatement() diff --git a/Upsilon/Parser/StatementSyntax/BreakStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/BreakStatementSyntax.cs index 1cd7d9e..bf204d7 100644 --- a/Upsilon/Parser/StatementSyntax/BreakStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/BreakStatementSyntax.cs @@ -8,6 +8,7 @@ namespace Upsilon.Parser public BreakStatementSyntax(SyntaxToken breakKeyword) { BreakKeyword = breakKeyword; + Span = breakKeyword.Span; } public override SyntaxKind Kind => SyntaxKind.BreakStatement; diff --git a/Upsilon/Parser/StatementSyntax/ExpressionStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/ExpressionStatementSyntax.cs index 1916aea..c55b25d 100644 --- a/Upsilon/Parser/StatementSyntax/ExpressionStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/ExpressionStatementSyntax.cs @@ -9,6 +9,7 @@ namespace Upsilon.Parser public ExpressionStatementSyntax(ExpressionSyntax expression) { Expression = expression; + Span = expression.Span; } public override SyntaxKind Kind => SyntaxKind.ExpressionStatement; diff --git a/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs index 8784a14..a041563 100644 --- a/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/FunctionAssignmentStatementSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -9,6 +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); } public SyntaxToken LocalToken { get; } diff --git a/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs index 9acacce..22b5935 100644 --- a/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/GenericForStatementSyntax.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Upsilon.Text; namespace Upsilon.Parser { @@ -23,6 +24,7 @@ namespace Upsilon.Parser DoKeyword = doKeyword; Block = block; EndKeyword = endKeyword; + Span = new TextSpan(forKeyword.Span.Start, endKeyword.Span.End - forKeyword.Span.Start); } public override SyntaxKind Kind => SyntaxKind.GenericForStatement; diff --git a/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs index 9d08e14..3c1debf 100644 --- a/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/IfStatementSyntax.cs @@ -16,7 +16,7 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; EndToken = endToken; - + Span = new TextSpan(IfToken.Span.Start, EndToken.Span.End - IfToken.Span.Start); } public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, @@ -27,7 +27,7 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; ElseStatement = elseStatement; - + Span = new TextSpan(IfToken.Span.Start, EndToken.Span.End - IfToken.Span.Start); } public IfStatementSyntax(SyntaxToken ifToken, ExpressionStatementSyntax condition, SyntaxToken thenToken, @@ -38,6 +38,7 @@ namespace Upsilon.Parser ThenToken = thenToken; Block = block; NextElseIfStatement = nextElseIfStatement; + Span = new TextSpan(IfToken.Span.Start, NextElseIfStatement.Span.End - IfToken.Span.Start); } @@ -76,6 +77,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); } public ElseIfStatementSyntax(IfStatementSyntax s) @@ -115,6 +117,7 @@ namespace Upsilon.Parser ElseToken = elseToken; Block = block; EndToken = endToken; + Span = new TextSpan(ElseToken.Span.Start, EndToken.Span.End - ElseToken.Span.Start); } public override SyntaxKind Kind => SyntaxKind.ElseStatement; diff --git a/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs index d2a9ffb..dd98fa1 100644 --- a/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/MultiAssignmentStatementSyntax.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; +using Upsilon.Text; namespace Upsilon.Parser { @@ -17,6 +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); } public override SyntaxKind Kind => SyntaxKind.MultiAssignmentStatement; diff --git a/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs index 8ae2161..f900ea5 100644 --- a/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/NumericForStatementSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -31,6 +32,7 @@ namespace Upsilon.Parser DoToken = doToken; Block = block; EndToken = endToken; + Span = new TextSpan(ForToken.Span.Start, EndToken.Span.End - ForToken.Span.Start); } public override SyntaxKind Kind => SyntaxKind.NumericForStatement; diff --git a/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs index b448f6b..e4d0241 100644 --- a/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/ReturnStatementSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -8,6 +9,7 @@ namespace Upsilon.Parser { ReturnToken = returnToken; Expression = expression; + Span = new TextSpan(returnToken.Span.Start, expression.Span.End - returnToken.Span.Start); } public SyntaxToken ReturnToken { get; } diff --git a/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs b/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs index c93627d..cf3a8b0 100644 --- a/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs +++ b/Upsilon/Parser/StatementSyntax/TableAssigmentStatementSyntax.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Upsilon.Text; namespace Upsilon.Parser { @@ -14,6 +15,7 @@ namespace Upsilon.Parser TableExpression = tableExpression; AssignmentToken = assignmentToken; Expression = expression; + Span = new TextSpan(tableExpression.Span.Start, expression.Span.End - tableExpression.Span.Start); } public override SyntaxKind Kind => SyntaxKind.TableAssignmentStatement; diff --git a/Upsilon/Text/SourceText.cs b/Upsilon/Text/SourceText.cs index 6b5b098..f050680 100644 --- a/Upsilon/Text/SourceText.cs +++ b/Upsilon/Text/SourceText.cs @@ -41,6 +41,11 @@ namespace Upsilon.Text while (min <= max) { 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) { @@ -56,6 +61,11 @@ namespace Upsilon.Text max = mid - 1; } } + + if (min >= _lines.Length) + { + min = _lines.Length - 1; + } var newPos = spanPos - _lines[min].Start; return (min, newPos); } @@ -65,6 +75,16 @@ namespace Upsilon.Text return _lines[lineIndex].Start; } + public int GetLineCount() + { + return _lines.Length; + } + + public int GetTextLength() + { + return _text.Length; + } + public SourceTextLine GetLineInfo(int lineIndex) { return _lines[lineIndex]; diff --git a/UpsilonTests/GeneralTests/UserDataTests.cs b/UpsilonTests/GeneralTests/UserDataTests.cs index 25ebcef..a9f2b34 100644 --- a/UpsilonTests/GeneralTests/UserDataTests.cs +++ b/UpsilonTests/GeneralTests/UserDataTests.cs @@ -106,7 +106,7 @@ end Assert.Empty(script.Diagnostics.Messages); var result = script.EvaluateFunction("test", new[] {obj}); Assert.Empty(script.Diagnostics.Messages); - Assert.Equal(result, 120); + Assert.Equal(120, result); } [Fact]