300 lines
12 KiB
VB.net
300 lines
12 KiB
VB.net
#Region "Microsoft.VisualBasic::b2cd970053bb67e06a981980690c5b2c, R#\Language\Syntax\SyntaxImplements\VectorLiteral.vb"
|
|
|
|
' Author:
|
|
'
|
|
' asuka (amethyst.asuka@gcmodeller.org)
|
|
' xie (genetics@smrucc.org)
|
|
' xieguigang (xie.guigang@live.com)
|
|
'
|
|
' Copyright (c) 2018 GPL3 Licensed
|
|
'
|
|
'
|
|
' GNU GENERAL PUBLIC LICENSE (GPL3)
|
|
'
|
|
'
|
|
' This program is free software: you can redistribute it and/or modify
|
|
' it under the terms of the GNU General Public License as published by
|
|
' the Free Software Foundation, either version 3 of the License, or
|
|
' (at your option) any later version.
|
|
'
|
|
' This program is distributed in the hope that it will be useful,
|
|
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
' GNU General Public License for more details.
|
|
'
|
|
' You should have received a copy of the GNU General Public License
|
|
' along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
' /********************************************************************************/
|
|
|
|
' Summaries:
|
|
|
|
|
|
' Code Statistics:
|
|
|
|
' Total Lines: 244
|
|
' Code Lines: 196 (80.33%)
|
|
' Comment Lines: 14 (5.74%)
|
|
' - Xml Docs: 35.71%
|
|
'
|
|
' Blank Lines: 34 (13.93%)
|
|
' File Size: 10.87 KB
|
|
|
|
|
|
' Module VectorLiteralSyntax
|
|
'
|
|
' Function: GetVectorElements, LiteralSyntax, ParseAnnotation, ParseAnnotations, (+2 Overloads) SequenceLiteral
|
|
' TypeCodeOf, VectorLiteral
|
|
'
|
|
'
|
|
' /********************************************************************************/
|
|
|
|
#End Region
|
|
|
|
Imports System.Runtime.CompilerServices
|
|
Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Diagnostics
|
|
Imports Microsoft.VisualBasic.ComponentModel.Collection
|
|
Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
|
|
Imports Microsoft.VisualBasic.Language
|
|
Imports Microsoft.VisualBasic.Linq
|
|
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine
|
|
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine.ExpressionSymbols
|
|
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine.ExpressionSymbols.DataSets
|
|
Imports SMRUCC.Rsharp.Language.TokenIcer
|
|
Imports SMRUCC.Rsharp.Runtime.Components
|
|
|
|
Namespace Language.Syntax.SyntaxParser.SyntaxImplements
|
|
|
|
Module VectorLiteralSyntax
|
|
|
|
Public Function LiteralSyntax(token As Token, opts As SyntaxBuilderOptions) As SyntaxResult
|
|
Select Case token.name
|
|
Case TokenType.booleanLiteral
|
|
Return New Literal With {.m_type = TypeCodes.boolean, .value = token.text.ParseBoolean}
|
|
Case TokenType.integerLiteral
|
|
Return New Literal With {.m_type = TypeCodes.integer, .value = CLng(token.text.ParseInteger)}
|
|
Case TokenType.numberLiteral
|
|
Return New Literal With {.m_type = TypeCodes.double, .value = token.text.ParseDouble}
|
|
Case TokenType.stringLiteral, TokenType.cliShellInvoke
|
|
Return New Literal With {.m_type = TypeCodes.string, .value = token.text}
|
|
Case TokenType.missingLiteral
|
|
Dim type As TypeCodes = TypeCodes.NA
|
|
Dim value As Object
|
|
|
|
Select Case token.text
|
|
' null literal for R/python/javascript
|
|
Case "NULL", "None", "null" : value = Nothing
|
|
Case "NA" : value = GetType(Void)
|
|
Case "Inf" : value = Double.PositiveInfinity
|
|
Case Else
|
|
Return SyntaxResult.CreateError(
|
|
err:=New SyntaxErrorException($"Unknown literal token: {token.ToString}"),
|
|
opts:=opts.SetCurrentRange({token})
|
|
)
|
|
End Select
|
|
|
|
Return New Literal With {
|
|
.m_type = type,
|
|
.value = value
|
|
}
|
|
Case Else
|
|
Return SyntaxResult.CreateError(
|
|
err:=New InvalidExpressionException(token.ToString),
|
|
opts:=opts.SetCurrentRange({token})
|
|
)
|
|
End Select
|
|
End Function
|
|
|
|
<Extension>
|
|
Public Iterator Function ParseAnnotations(blocks As Token()) As IEnumerable(Of NamedValue(Of String))
|
|
For Each block As Token() In blocks.Split(4)
|
|
Yield block.Skip(1).Take(2).ToArray.ParseAnnotation
|
|
Next
|
|
End Function
|
|
|
|
<Extension>
|
|
Public Function ParseAnnotation(block As Token()) As NamedValue(Of String)
|
|
Dim name As String = block(Scan0).text.Substring(1)
|
|
Dim value As String = block(1).text
|
|
|
|
Return New NamedValue(Of String)(name, value)
|
|
End Function
|
|
|
|
<Extension>
|
|
Private Function GetVectorElements(tokens As Token()) As List(Of Token())
|
|
tokens = tokens _
|
|
.Skip(1) _
|
|
.Take(tokens.Length - 2) _
|
|
.ToArray
|
|
|
|
Dim isSimples As Boolean = tokens _
|
|
.All(Function(a)
|
|
Return a.isLiteral OrElse
|
|
a.name = TokenType.stringInterpolation OrElse
|
|
a.name = TokenType.identifier OrElse
|
|
a.name = TokenType.keyword
|
|
End Function)
|
|
|
|
If isSimples Then
|
|
Return tokens.Select(Function(a) New Token() {a}).AsList
|
|
Else
|
|
Return tokens.SplitByTopLevelDelimiter(TokenType.comma)
|
|
End If
|
|
End Function
|
|
|
|
Public Function VectorLiteral(tokens As Token(), opts As SyntaxBuilderOptions) As SyntaxResult
|
|
Dim blocks As List(Of Token()) = tokens.GetVectorElements
|
|
Dim values As New List(Of Expression)
|
|
Dim syntaxTemp As SyntaxResult
|
|
|
|
If blocks Is Nothing AndAlso tokens.Last.name = TokenType.cliShellInvoke Then
|
|
Dim cli = CommandLineSyntax.CommandLine(tokens.Last, opts)
|
|
|
|
If cli.isException Then
|
|
Return cli
|
|
End If
|
|
|
|
blocks = tokens _
|
|
.Skip(1) _
|
|
.Take(tokens.Length - 3) _
|
|
.SplitByTopLevelDelimiter(TokenType.comma)
|
|
|
|
Dim annotation As NamedValue(Of String) = blocks(Scan0).ParseAnnotation
|
|
DirectCast(cli.expression, ExternalCommandLine).SetAttribute(annotation)
|
|
Return cli
|
|
ElseIf blocks.Count = 1 AndAlso blocks(Scan0).Length = 2 Then
|
|
Dim block As Token() = blocks(Scan0)
|
|
|
|
' is user annotation
|
|
If block(Scan0).name = TokenType.annotation AndAlso block(1).isLiteral Then
|
|
Dim annotation As NamedValue(Of String) = block.ParseAnnotation
|
|
Call opts.annotations.Add(annotation)
|
|
Return New CodeComment($"{annotation.Name}:={annotation.Value}")
|
|
End If
|
|
End If
|
|
|
|
For Each block As Token() In blocks
|
|
' is a comma symbol
|
|
If block.Length = 1 AndAlso block(Scan0).name = TokenType.comma Then
|
|
Continue For
|
|
End If
|
|
|
|
syntaxTemp = block.DoCall(Function(code) opts.ParseExpression(code, opts))
|
|
|
|
If syntaxTemp.isException Then
|
|
Return syntaxTemp
|
|
Else
|
|
values.Add(syntaxTemp.expression)
|
|
End If
|
|
Next
|
|
|
|
' 还会剩余最后一个元素
|
|
' 所以在这里需要加上
|
|
Return New SyntaxResult(New VectorLiteral(values, values.DoCall(AddressOf TypeCodeOf)))
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' get type code value of the vector literal
|
|
''' </summary>
|
|
''' <param name="values"></param>
|
|
''' <returns></returns>
|
|
<MethodImpl(MethodImplOptions.AggressiveInlining)>
|
|
Friend Function TypeCodeOf(values As IEnumerable(Of Expression)) As TypeCodes
|
|
With values.ToArray
|
|
' fix for System.InvalidOperationException: Nullable object must have a value.
|
|
'
|
|
If .Length = 0 Then
|
|
Return TypeCodes.generic
|
|
ElseIf .Length = 1 Then
|
|
Return DirectCast(.GetValue(Scan0), Expression).type
|
|
Else
|
|
' generic > string > double > float > long > integer > byte > boolean
|
|
Static typeCodeWeights As Index(Of TypeCodes) = {
|
|
TypeCodes.boolean,
|
|
TypeCodes.integer,
|
|
TypeCodes.double,
|
|
TypeCodes.string,
|
|
TypeCodes.generic
|
|
}
|
|
|
|
' get unique types
|
|
Dim types As TypeCodes() = .Select(Function(exp)
|
|
Dim t = exp.type
|
|
|
|
If t = TypeCodes.NA Then
|
|
t = TypeCodes.generic
|
|
End If
|
|
|
|
Return t
|
|
End Function) _
|
|
.Distinct _
|
|
.ToArray
|
|
If types.Length = 1 Then
|
|
Return types(Scan0)
|
|
Else
|
|
Dim maxType As TypeCodes = TypeCodes.boolean
|
|
Dim maxWeight As Integer
|
|
|
|
For Each code As TypeCodes In types
|
|
If typeCodeWeights.IndexOf(code) > maxWeight Then
|
|
maxType = code
|
|
maxWeight = typeCodeWeights(maxType)
|
|
End If
|
|
Next
|
|
|
|
Return maxType
|
|
End If
|
|
End If
|
|
End With
|
|
End Function
|
|
|
|
Public Function SequenceLiteral(from As Token, [to] As Token, steps As Token, opts As SyntaxBuilderOptions) As SyntaxResult
|
|
Return SequenceLiteral({from}, {[to]}, {steps}, opts)
|
|
End Function
|
|
|
|
Public Function SequenceLiteral(from As Token(), [to] As Token(), steps As Token(), opts As SyntaxBuilderOptions) As SyntaxResult
|
|
Dim fromSyntax = opts.ParseExpression(from, opts)
|
|
Dim toSyntax = opts.ParseExpression([to], opts)
|
|
Dim sourceMap As StackFrame = opts.GetStackTrace(from(Scan0), "sequence")
|
|
|
|
If fromSyntax.isException Then
|
|
Return fromSyntax
|
|
ElseIf toSyntax.isException Then
|
|
Return toSyntax
|
|
End If
|
|
|
|
If steps.IsNullOrEmpty Then
|
|
Return New SequenceLiteral(fromSyntax.expression, toSyntax.expression, New Literal(1), sourceMap)
|
|
ElseIf steps.isLiteral Then
|
|
Dim stepLiteral As SyntaxResult = SyntaxImplements.LiteralSyntax(steps(Scan0), opts)
|
|
|
|
If stepLiteral.isException Then
|
|
Return stepLiteral
|
|
End If
|
|
|
|
Return New SequenceLiteral(
|
|
from:=fromSyntax.expression,
|
|
[to]:=toSyntax.expression,
|
|
steps:=stepLiteral.expression,
|
|
stackFrame:=sourceMap
|
|
)
|
|
Else
|
|
Dim stepsSyntax As SyntaxResult = opts.ParseExpression(steps, opts)
|
|
|
|
If stepsSyntax.isException Then
|
|
Return stepsSyntax
|
|
Else
|
|
Return New SequenceLiteral(
|
|
from:=fromSyntax.expression,
|
|
[to]:=toSyntax.expression,
|
|
steps:=stepsSyntax.expression,
|
|
stackFrame:=sourceMap
|
|
)
|
|
End If
|
|
End If
|
|
End Function
|
|
End Module
|
|
End Namespace
|