Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VB -> C#: Query Expression Syntax not fully implemented #29

Closed
malbert69 opened this issue Feb 22, 2018 · 15 comments
Closed

VB -> C#: Query Expression Syntax not fully implemented #29

malbert69 opened this issue Feb 22, 2018 · 15 comments
Labels
help wanted VB -> C# Specific to VB -> C# conversion

Comments

@malbert69
Copy link

malbert69 commented Feb 22, 2018

Tried converting the following...

Large code snippet containing various query syntax Imports System.Data Imports System.IO Imports FCA Imports FCA.Data Imports Legacy
Namespace Admin

    Partial Public Class PrintConsignmentAreaRugCards
        Inherits Page

        Dim _currentUser As MpMembershipUser

        Private Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
            _currentUser = Globals.GetCurrentMpUser()
        End Sub

        Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
            If TextBox1.Text.Trim = String.Empty Then
                MIAIDLabel.Text = "Not found."
                AddLinkButton.Enabled = False
                Exit Sub
            End If

            Using OrderData = New MpOrderDataSet()
                Dim Item =
                        OrderData.GetItemRowByFilter(_currentUser.Location, "reg_num=? AND ptype='29'", TextBox1.Text)
                If Not Item Is Nothing Then
                    MIAIDLabel.Text = Item.mia_id.ToString()
                    AddLinkButton.Enabled = True
                Else
                    MIAIDLabel.Text = "Not found."
                    AddLinkButton.Enabled = False
                End If
            End Using
        End Sub

        Private Sub AddLinkButton_Click(sender As Object, e As EventArgs) Handles AddLinkButton.Click
            If MIAIDLabel.Text.Trim = "" OrElse ListBox1.Items.Cast(Of ListItem).Any(Function(item) item.Value = MIAIDLabel.Text) Then
                Exit Sub
            End If
            ListBox1.Items.Add(New ListItem(TextBox1.Text, MIAIDLabel.Text))
        End Sub

        Private Sub PrintConsignmentAreaRugCards_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
            If ListBox1.Items.Count = 0 Then
                SheetCountLabel.Text = "No sheets needed."
            Else
                If CDec(ListBox1.Items.Count / 4) = CDec(Math.Truncate(ListBox1.Items.Count / 4)) Then
                    SheetCountLabel.Text = CStr(Math.Truncate(ListBox1.Items.Count / 4)) & " sheets needed."
                Else
                    SheetCountLabel.Text = CStr(Math.Truncate(ListBox1.Items.Count / 4) + 1) & " sheets needed."
                End If
            End If
        End Sub

        Private Sub DeleteLinkButton_Click(sender As Object, e As EventArgs) Handles DeleteLinkButton.Click
            If ListBox1.SelectedIndex = -1 Then Exit Sub
            ListBox1.Items.RemoveAt(ListBox1.SelectedIndex)
        End Sub

        Private Sub PrintThisLabelButton_Click(sender As Object, e As EventArgs) Handles PrintThisLabelButton.Click
            If ListBox1.Items.Count = 0 Then Exit Sub
            Dim MIAIDList As String = String.Join(",", ListBox1.Items.Cast(Of ListItem).Select(Function(item) item.Value))
            'For Each item As ListItem In ListBox1.Items
            '    MIAIDList &= item.Value & ","
            'Next
            'MIAIDList = MIAIDList.TrimEnd(","c)
            GetPicList()
            Dim Query As String = String.Format("SELECT c.desc AS origin," +
"'0'+RIGHT(RTRIM(p1.sty_link),5) AS rug_id," +
"p2.prv_sku,prv_style AS description,'' AS picture," +
"0 AS our_price,0 AS suggested " +
"FROM `..\{0}\item{0}` i " +
"INNER JOIN `..\..\common\prodcat2` p2 ON p2.prv_sku=i.color " +
"INNER JOIN `..\..\common\prodcat1` p1 ON p1.sty_link=p2.sty_link " +
"LEFT JOIN `..\..\common\codes` c ON c.code=p1.attrib_5 " +
"WHERE p1.prodtype='29' AND c.type='A0529' AND i.mia_id IN ({1})", _currentUser.Location, MIAIDList)
            Using Table As DataTable = Service.GetDataTable(_currentUser.Location, Query)
                If Table IsNot Nothing Then
                    If Table.Rows.Count > 0 Then
                        Dim DV As DataView = Table.DefaultView
                        Dim Drv As DataRowView
                        Dim PrvSKU As String
                        Dim SuggestedPrice As Decimal
                        Dim OurPrice As Decimal
                        For i = 0 To DV.Count - 1
                            Drv = DV.Item(i)
                            PrvSKU = CStr(Drv.Item("prv_sku"))
                            SuggestedPrice = 0
                            OurPrice = 0
                            Globals.GetConsignmentAreaRugRetailPrices(PrvSKU, SuggestedPrice, OurPrice)
                            Drv.Item("our_price") = OurPrice
                            Drv.Item("suggested") = SuggestedPrice
                            Drv.Item("picture") = FindPicFilePath(CStr(Drv.Item("rug_id")))
                        Next
                    End If
                    ConsignmentAreaRugCardCrystalReportSource.ReportDocument.SetDataSource(Table)
                    ConsignmentAreaRugCardCrystalReportSource.DataBind()
                    CrystalReportViewer.Visible = True
                End If
            End Using
        End Sub

        Private Shared Sub GetPicList()
            Dim DirectoryInfo As New DirectoryInfo("\\m-5\rugpics")
            SiteSession.Current.AreaRugPicsFileInfoList = DirectoryInfo.GetFiles("*.jpg")
        End Sub

        Private Shared Function FindPicFilePath(picId As String) As String
            For Each FileInfo As FileInfo In From FileInfo1 In SiteSession.Current.AreaRugPicsFileInfoList Where FileInfo1.Name.Substring(0, 6) = picId
                Return FileInfo.FullName
            Next
            Return String.Empty
        End Function

        Private Sub PrintThemAllButton_Click(sender As Object, e As EventArgs) Handles PrintThemAllButton.Click
            GetPicList()
            Dim Query As String =
                    String.Concat("SELECT c.desc AS origin,",
                                  "'0'+RIGHT(RTRIM(p1.sty_link),5) AS rug_id,p2.prv_sku,prv_style AS description,'' AS picture,",
                                  "0 AS our_price,0 AS suggested ",
                                  "FROM prodcat1 p1 ",
                                  "INNER JOIN prodcat2 p2 ",
                                  "ON p1.sty_link=p2.sty_link ",
                                  "LEFT JOIN codes c ",
                                  "ON c.code=p1.attrib_5 ",
                                  "WHERE p1.prodtype='29' ",
                                  "AND c.type='A0529'")
            Using Table As DataTable = Service.GetDataTable("COMMON", Query)
                If Table IsNot Nothing Then
                    If Table.Rows.Count > 0 Then
                        Dim DV As DataView = Table.DefaultView
                        For i = 0 To DV.Count - 1
                            Dim Drv As DataRowView = DV.Item(i)
                            Dim PrvSKU As String = CStr(Drv.Item("prv_sku"))
                            Dim SuggestedPrice As Decimal = 0
                            Dim OurPrice As Decimal = 0
                            ConsignmentAreaRugLabelLayout.GetRetailPrices(PrvSKU, SuggestedPrice, OurPrice)
                            Drv.Item("our_price") = OurPrice
                            Drv.Item("suggested") = SuggestedPrice
                            Drv.Item("picture") = FindPicFilePath(CStr(Drv.Item("rug_id")))
                        Next
                    End If
                    ConsignmentAreaRugCardCrystalReportSource.ReportDocument.SetDataSource(Table)
                    ConsignmentAreaRugCardCrystalReportSource.DataBind()
                    CrystalReportViewer.Visible = True
                End If
            End Using
        End Sub
    End Class
End Namespace
@GrahamTheCoder
Copy link
Member

Thanks for raising the issue. I've made a start on very basic query expression syntax which I think I'll try to get released soon. Visual Basic has slightly more features in its query syntax, so it'd take quite a bit more effort to support every possible case. I'll leave this issue open since even if your repro might be fixed, others may come along and upvote further work in this area.

@GrahamTheCoder GrahamTheCoder changed the title VB to C# Error Microsoft.CodeAnalysis.VisualBasic.Syntax.QueryExpressionSyntax not implemented! VB to C# Query Expression Syntax not fully implemented Feb 25, 2018
@BaronBodissey
Copy link

Hello,
I'd like to help in the context of my needs. For example as for now I've at least 5 features I need:
System.NotSupportedException: IntegerDivideExpression not supported!
System.NotSupportedException: NarrowingKeyword not supported!
System.NotImplementedException: Microsoft.CodeAnalysis.VisualBasic.Syntax.ReDimStatementSyntax not implemented!
System.NotSupportedException: IsExpression not supported!
System.NotSupportedException: PlusToken not supported!

How can I help?

@GrahamTheCoder
Copy link
Member

GrahamTheCoder commented Mar 5, 2018

Hi, thanks for getting in touch. I don't think those are related to this issue, but they are all things that can be worked on. If you're up for making changes, I'd suggest working on NarrowingKeyword first.

  • Create a separate issue for the thing you're working on (ReDim is covered in Known limitations #16)
  • Fork the repo
  • Write a test in ExpressionTests that shows the error happening
  • Add an override in NodesVisitor to handle that syntax type.

Here's an example of a PR that has a similar kind of shape to what you'll need to do:
https://github.com/icsharpcode/CodeConverter/pull/26/files

Let me know (on a PR or issue comment) if you need more help - if you can push any code changes you make, and provide examples of what code snippet won't work it'll really help.

@GrahamTheCoder
Copy link
Member

@BaronBodissey I've now merged changes to support IntegerDivideExpression and IsExpression. If you could find which bit of code which threw the exception about PlusToken that'd be really helpful, otherwise the callstack of the exception might be enough to repro.

@BaronBodissey
Copy link

BaronBodissey commented Mar 13, 2018

@GrahamTheCoder I'm currently working on this issue and several others. I intend to commit today for you to check if my coding is okay.

@BaronBodissey
Copy link

@GrahamTheCoder Soooorry I'm kinda new in here on github. I didn't understood your comment about PlusToken. With the PR I released, and your comments I do understand now. Do you still need help about it?

@GrahamTheCoder
Copy link
Member

@BaronBodissey No problem, everyone's new sometime! Yes any extra information about the PlusToken error would be great.
Either the stacktrace when the error happens, or a small section of source code that causes it when converted would be very helpful.

@GrahamTheCoder GrahamTheCoder changed the title VB to C# Query Expression Syntax not fully implemented VB -> C#: Query Expression Syntax not fully implemented Mar 23, 2018
@GrahamTheCoder GrahamTheCoder added the VB -> C# Specific to VB -> C# conversion label Apr 9, 2018
@camainc
Copy link

camainc commented May 1, 2018

Any idea when this feature will be implemented? I have a bunch of vb that needs to be converted, and this one keeps biting me.

Thanks

@GrahamTheCoder
Copy link
Member

GrahamTheCoder commented May 2, 2018

I've been putting it off because I'm not very familiar with vb's query syntax, so the thing I'm worried about is subtly changing the behavior of the code without realizing. It's possible some useful information can be gleaned from either the roslyn API or by following a pattern from the compiler itself.

Ideally I'd have some examples of complex queries to test against. If you can provide any examples of queries you're trying to convert it'd help. I'd also be very happy to accept a pr either just containing just test cases, or with some improved implementation if you want to contribute directly.

Now that someone is actively interested in the result, I will try to make some improvements in the next 2 weeks. Thanks for posting.

@GrahamTheCoder GrahamTheCoder self-assigned this May 2, 2018
@camainc
Copy link

camainc commented May 2, 2018

I can send you a couple of samples that I manually converted. I'm not very familiar with VB's syntax either, that's why I was leaning on you guys :-)

@GrahamTheCoder
Copy link
Member

I put together a simple test case covering some of the broken stuff:

        [Fact]
        public void LinqPartitionDistinct()
        {
            TestConversionVisualBasicToCSharp(@"Private Shared Function FindPicFilePath() As IEnumerable(Of String)
    Dim words = {""an"", ""apple"", ""a"", ""day"", ""keeps"", ""the"", ""doctor"", ""away""}

    Return From word In words
            Skip 1
            Skip While word.Length >= 1
            Take While word.Length < 5
            Take 2
            Distinct
End Function", @"private static IEnumerable<string> FindPicFilePath()
{
    var words = new[] {""an"", ""apple"", ""a"", ""day"", ""keeps"", ""the"", ""doctor"", ""away""};
    return words
        .Skip(1)
        .SkipWhile(word => word.Length >= 1)
        .TakeWhile(word => word.Length < 5)
        .Take(2)
        .Distinct();
}");
        }

When seen like that it looks so simple, but unfortunately I don't think I'll have time to work on this for a few weeks now since I'm away on holiday.

@GrahamTheCoder
Copy link
Member

@camainc Please add any other examples you have in the comments here and I'll turn them into tests

@camainc
Copy link

camainc commented May 29, 2018 via email

@GrahamTheCoder
Copy link
Member

GrahamTheCoder commented Apr 25, 2019

I recently discovered: a Roslyn C# only query syntax to method chain converter. For the C# -> VB direction, it'd be possible to run this as a pre-step, then normal method conversion would work. It's possible something similar already exists for VB.

I'm still hoping that the compiler itself may have an implementation we can use contained within it. Here's the example ILSpy output which does end up calling the Skip and Take methods as you would expect. The question is, did all those classes get generated for the closures separately, or intertwined. If it's intertwined we might not be able to easily get the arguments for each function out since even ILSpy doesn't manage to display this perfectly as lambdas

	return source.Skip(1).SkipWhile((_Closure$__.$I3-0 != null) ? _Closure$__.$I3-0 : (_Closure$__.$I3-0 = ((string word) => word.Length >= 1)))
                .TakeWhile((_Closure$__.$I3-1 != null) ? _Closure$__.$I3-1 : (_Closure$__.$I3-1 = ((string word) => word.Length < 5)))
		.Take(2)
		.Distinct();

[Serializable]
[CompilerGenerated]
internal sealed class _Closure$__
{
	public static readonly _Closure$__ $I;

	public static Func<string, bool> $I3-0;

	public static Func<string, bool> $I3-1;

	static _Closure$__()
	{
		$I = new _Closure$__();
	}

	internal bool _Lambda$__3-0(string word)
	{
		return word.Length >= 1;
	}

	internal bool _Lambda$__3-1(string word)
	{
		return word.Length < 5;
	}
}

Needs more investigation. It might be that we can get ILSpy to handle this case and use that directly if Roslyn doesn't have an easier way built-in.

@GrahamTheCoder GrahamTheCoder modified the milestone: When more users request Mar 20, 2020
@GrahamTheCoder
Copy link
Member

Now that the basic syntax is covered, I'm going to close this overarching issue and try to deal with individual cases as they come up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted VB -> C# Specific to VB -> C# conversion
Projects
None yet
Development

No branches or pull requests

4 participants