diff --git a/LINQ/LINQ/Interpreter/Expressions/ArrayExpression.vb b/LINQ/LINQ/Interpreter/Expressions/ArrayExpression.vb index ac501c1..f3b935e 100644 --- a/LINQ/LINQ/Interpreter/Expressions/ArrayExpression.vb +++ b/LINQ/LINQ/Interpreter/Expressions/ArrayExpression.vb @@ -1,6 +1,17 @@ -Namespace Interpreter.Expressions +Imports LINQ.Runtime - Public Class ArrayExpression +Namespace Interpreter.Expressions + Public Class ArrayExpression : Inherits Expression + + Dim seq As Expression() + + Sub New(seq As IEnumerable(Of Expression)) + Me.seq = seq.ToArray + End Sub + + Public Overrides Function Exec(env As Environment) As Object + Throw New NotImplementedException() + End Function End Class End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/Interpreter/Query/ProjectionExpression.vb b/LINQ/LINQ/Interpreter/Query/ProjectionExpression.vb index 109d54b..84aaad8 100644 --- a/LINQ/LINQ/Interpreter/Query/ProjectionExpression.vb +++ b/LINQ/LINQ/Interpreter/Query/ProjectionExpression.vb @@ -13,8 +13,10 @@ Namespace Interpreter.Query Dim symbol As SymbolDeclare Dim executeQueue As Expression() - Sub New(exec As IEnumerable(Of Expression)) - executeQueue = exec.ToArray + Sub New(symbol As SymbolDeclare, sequence As Expression, exec As IEnumerable(Of Expression)) + Me.executeQueue = exec.ToArray + Me.symbol = symbol + Me.sequence = sequence End Sub Public Overrides Function Exec(env As Environment) As Object diff --git a/LINQ/LINQ/Language/Token.vb b/LINQ/LINQ/Language/Token.vb index c5591d5..123d0c5 100644 --- a/LINQ/LINQ/Language/Token.vb +++ b/LINQ/LINQ/Language/Token.vb @@ -7,5 +7,14 @@ Namespace Language Sub New(name As Tokens, Optional text As String = Nothing) Call MyBase.New(name, text) End Sub + + Public Overloads Shared Operator =(t As Token, c As (name As Tokens, text As String)) As Boolean + Return t.name = c.name AndAlso t.text = c.text + End Operator + + Public Overloads Shared Operator <>(t As Token, c As (name As Tokens, text As String)) As Boolean + Return Not t = c + End Operator + End Class End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/Script/StackParser.vb b/LINQ/LINQ/Script/StackParser.vb index 48569ce..e1c5e4b 100644 --- a/LINQ/LINQ/Script/StackParser.vb +++ b/LINQ/LINQ/Script/StackParser.vb @@ -5,16 +5,22 @@ Imports Microsoft.VisualBasic.Language Module StackParser - Private Function isKeywordFrom(t As Token) As Boolean + Friend Function isKeywordFrom(t As Token) As Boolean Return isKeyword(t, "from") End Function - Private Function isKeyword(t As Token, text As String) As Boolean + + Friend Function isKeywordAggregate(t As Token) As Boolean + Return isKeyword(t, "aggregate") + End Function + + + Friend Function isKeyword(t As Token, text As String) As Boolean Return t.name = Tokens.keyword AndAlso t.text.TextEquals(text) End Function - Private Function isKeywordSelect(t As Token) As Boolean + Friend Function isKeywordSelect(t As Token) As Boolean Return isKeyword(t, "select") End Function @@ -30,7 +36,20 @@ Module StackParser Public Iterator Function SplitByTopLevelStack(tokenList As IEnumerable(Of Token)) As IEnumerable(Of Token()) - For Each block In tokenList.DoSplitByTopLevelStack + For Each block In tokenList.DoSplitByTopLevelStack(Function(t) + Return t.name = Tokens.keyword AndAlso Not t.text.TextEquals("as") + End Function) + If Not block.All(Function(t) t.name = Tokens.Terminator) Then + Yield block + End If + Next + End Function + + + Public Iterator Function SplitParameters(tokenList As IEnumerable(Of Token)) As IEnumerable(Of Token()) + For Each block In tokenList.DoSplitByTopLevelStack(Function(t) + Return t.name = Tokens.Comma + End Function) If Not block.All(Function(t) t.name = Tokens.Terminator) Then Yield block End If @@ -43,12 +62,12 @@ Module StackParser ''' ''' - Private Iterator Function DoSplitByTopLevelStack(tokenList As IEnumerable(Of Token)) As IEnumerable(Of Token()) + Private Iterator Function DoSplitByTopLevelStack(tokenList As IEnumerable(Of Token), delimiter As Func(Of Token, Boolean)) As IEnumerable(Of Token()) Dim block As New List(Of Token) Dim stack As New Stack(Of String) For Each item As Token In tokenList.Where(Function(t) t.name <> Tokens.Terminator AndAlso t.name <> Tokens.Comment) - If item.name = Tokens.keyword AndAlso Not item.text.TextEquals("as") Then + If delimiter(item) Then If stack.Count > 0 Then block.Add(item) Else diff --git a/LINQ/LINQ/Script/SyntaxImplements.vb b/LINQ/LINQ/Script/SyntaxImplements.vb index 1113b61..b2f5558 100644 --- a/LINQ/LINQ/Script/SyntaxImplements.vb +++ b/LINQ/LINQ/Script/SyntaxImplements.vb @@ -1,5 +1,6 @@ Imports System.Runtime.CompilerServices Imports LINQ.Interpreter.Expressions +Imports LINQ.Interpreter.Query Imports LINQ.Language Namespace Script @@ -10,11 +11,86 @@ Namespace Script Public Function PopulateQueryExpression(tokens As IEnumerable(Of Token)) As Expression Dim blocks = tokens.SplitByTopLevelStack.ToArray + If blocks(Scan0).First.isKeywordFrom Then + Return blocks(Scan0).CreateProjectionQuery(blocks.Skip(1).ToArray) + ElseIf blocks(Scan0).First.isKeywordAggregate Then + Return blocks(Scan0).CreateAggregateQuery(blocks.Skip(1).ToArray) + Else + Throw New SyntaxErrorException + End If + End Function + + + Private Function CreateProjectionQuery(symbol As Token(), blocks As Token()()) As ProjectionExpression + Dim symbolExpr As SymbolDeclare = symbol.ParseExpression + Dim i As Integer = 0 + Dim seq As Expression = blocks.GetSequence(offset:=i) + Dim exec As Expression() = blocks.Skip(i).PopulateExpressions.ToArray + Dim proj As New ProjectionExpression(symbolExpr, seq, exec) + + Return proj + End Function + + + Private Iterator Function PopulateExpressions(blocks As IEnumerable(Of Token())) As IEnumerable(Of Expression) + For Each blockLine As Token() In blocks + Yield ParseExpression(blockLine) + Next + End Function + + + Private Function GetSequence(blocks As Token()(), ByRef offset As Integer) As Expression + If Not blocks(Scan0).First.isKeyword("in") Then + Throw New SyntaxErrorException + ElseIf blocks(Scan0).Length = 1 Then + offset = 2 + Return blocks(1).ParseExpression + Else + offset = 1 + Return blocks(0).ParseExpression + End If + End Function + + Private Function CreateAggregateQuery(symbol As Token(), blocks As Token()()) As AggregateExpression + Dim symbolExpr As SymbolDeclare = symbol.ParseExpression + Dim seq As Expression End Function - Public Function ParseExpression(tokens As IEnumerable(Of Token)) As Expression + + Public Function ParseExpression(tokenList As Token()) As Expression + If tokenList(Scan0).isKeywordFrom OrElse tokenList(Scan0).isKeywordAggregate OrElse tokenList(Scan0).isKeyword("let") Then + ' declare new symbol + Dim name As String = tokenList(1).text + Dim type As String = "any" + + If tokenList.Length > 2 Then + type = tokenList(3).text + End If + + Return New SymbolDeclare With {.symbolName = name, .type = type} + End If + + Dim blocks = tokenList.SplitByTopLevelStack.ToArray + + If blocks.Length = 1 Then + tokenList = blocks(Scan0) + + If tokenList.First = (Tokens.Open, "[") OrElse tokenList.First = (Tokens.Open, "{") Then + Return tokenList.Skip(1).Take(tokenList.Length - 2).GetVector + End If + End If + + Throw New NotImplementedException + End Function + + + Private Function GetVector(tokenList As IEnumerable(Of Token)) As Expression + Dim blocks = tokenList.SplitParameters.Select(Function(b) If(b.Length = 1, b, b.Skip(1).ToArray)).ToArray + Dim elements As Expression() = blocks.Select(AddressOf ParseExpression).ToArray + Dim vec As New ArrayExpression(elements) + Return vec End Function End Module End Namespace \ No newline at end of file