Skip to content

Commit

Permalink
Added initial channel select statement handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ritchiecarroll committed Dec 29, 2024
1 parent 1752b7a commit 3d87f14
Show file tree
Hide file tree
Showing 24 changed files with 791 additions and 133 deletions.
76 changes: 76 additions & 0 deletions src/Tests/Behavioral/SelectStatement/SelectStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace go;

using fmt = fmt_package;

public static partial class main_package {

private static void g1(channel<nint> ch) {
ch.ᐸꟷ(12);
}

private static void g2(channel<nint> ch) {
ch.ᐸꟷ(32);
}

private static void sum(slice<nint> s, channel<nint> c) {
nint sum = 0;
foreach (var (_, v) in s) {
sum += v;
}
c.ᐸꟷ(sum);
}

private static void fibonacci(channel<nint> f, channel<nint> quit) {
nint x = 0;
nint y = 1;
while () {
switch (WhenAny(f.ᐸꟷ(x), quit.Receiving)) {
case 0:
(x, y) = (y, x + y);
break;
case 1 when ᐸꟷ(quit, OK).ok:
fmt.Println("quit");
return;
}
}
}

private static void Main() {
var ch = new channel<nint>(2);
ch.ᐸꟷ(1);
ch.ᐸꟷ(2);
fmt.Println(ᐸꟷ(ch));
fmt.Println(ᐸꟷ(ch));
var ch1 = new channel<nint>(1);
var ch2 = new channel<nint>(1);
goǃ(_ => g1(ch1));
goǃ(_ => g2(ch2));
switch (WhenAny(ch1.Receiving, ch2.Receiving)) {
case 0 when ch1.ꟷᐳ(out var v1):
fmt.Println("Got: ", v1);
break;
case 1 when ch2.ꟷᐳ(out var v2):
fmt.Println("Got: ", v2);
break;
}
var s = new nint[]{7, 2, 8, -9, 4, 0}.slice();
var c = new channel<nint>(1);
goǃ(_ => sum(s[..(int)(len(s) / 2)], c));
goǃ(_ => sum(s[(int)(len(s) / 2)..], c));
goǃ(_ => sum(s[2..5], c));
nint x = ᐸꟷ(c);
nint y = ᐸꟷ(c);
nint z = ᐸꟷ(c);
fmt.Println(x, y, x + y, z);
var f = new channel<nint>(1);
var quit = new channel<nint>(1);
goǃ(() => {
for (nint i = 0; i < 10; i++) {
fmt.Println(ᐸꟷ(f));
}
quit.ᐸꟷ(0);
});
fibonacci(f, quit);
}

} // end main_package
61 changes: 61 additions & 0 deletions src/Tests/Behavioral/SelectStatement/SelectStatement.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net9.0</TargetFrameworks>
<RootNamespace>go</RootNamespace>
<AssemblyName>SelectStatement</AssemblyName>
<Product>go2cs</Product>
<Copyright>Copyright © 2024</Copyright>
<PackageProjectUrl>https://github.com/GridProtectionAlliance/go2cs</PackageProjectUrl>
<RepositoryUrl>https://github.com/GridProtectionAlliance/go2cs</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<ApplicationIcon>go2cs.ico</ApplicationIcon>
<Nullable>enable</Nullable>
<NoWarn>660;661;IDE1006;CS8981</NoWarn>
<Version>0.1.4</Version>
<LangVersion>latest</LangVersion>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishTrimmed>True</PublishTrimmed>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(OutDir)'==''">
<OutDir>bin\$(Configuration)\$(TargetFramework)\</OutDir>
</PropertyGroup>

<ItemGroup>
<Using Include="go.builtin" Static="True" />
<Using Include="System.Byte" Alias="uint8" />
<Using Include="System.UInt16" Alias="uint16" />
<Using Include="System.UInt32" Alias="uint32" />
<Using Include="System.UInt64" Alias="uint64" />
<Using Include="System.SByte" Alias="int8" />
<Using Include="System.Int16" Alias="int16" />
<Using Include="System.Int32" Alias="int32" />
<Using Include="System.Int64" Alias="int64" />
<Using Include="System.Single" Alias="float32" />
<Using Include="System.Double" Alias="float64" />
<Using Include="System.Numerics.Complex" Alias="complex128" />
<Using Include="System.Int32" Alias="rune" />
<Using Include="System.UIntPtr" Alias="uintptr" />
<Using Include="System.Numerics.BigInteger" Alias="GoUntyped" />
<Using Include="System.ComponentModel.DescriptionAttribute" Alias="GoTag" />

<!-- Exclude the output of source generators from the compilation -->
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />

<!-- TODO: Add references to required projects -->
<ProjectReference Include="..\..\..\gocore\golib\golib.csproj" />
<ProjectReference Include="..\..\..\gocore\fmt\fmt.csproj" />
<ProjectReference Include="..\..\..\gocore\math\math.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\go2cs.CodeGenerators\go2cs.CodeGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="All" />
</ItemGroup>

</Project>
79 changes: 79 additions & 0 deletions src/Tests/Behavioral/SelectStatement/SelectStatement.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package main

import (
"fmt"
)

func g1(ch chan int) {
ch <- 12
}

func g2(ch chan int) {
ch <- 32
}

func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}

func fibonacci(f, quit chan int) {
x, y := 0, 1
for {
select {
case f <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}

func main() {
ch := make(chan int, 2)

ch <- 1
ch <- 2

fmt.Println(<-ch)
fmt.Println(<-ch)

ch1 := make(chan int)
ch2 := make(chan int)

go g1(ch1)
go g2(ch2)

select {
case v1 := <-ch1:
fmt.Println("Got: ", v1)
case v2 := <-ch2:
fmt.Println("Got: ", v2)
//default:
// fmt.Println("Default")
}

s := []int{7, 2, 8, -9, 4, 0}

c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
go sum(s[2:5], c)
x, y := <-c, <-c // receive from c
z := <-c
fmt.Println(x, y, x+y, z)

f := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-f)
}
quit <- 0
}()
fibonacci(f, quit)
}
Binary file added src/Tests/Behavioral/SelectStatement/go2cs.ico
Binary file not shown.
7 changes: 7 additions & 0 deletions src/go2cs.sln
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpreadOperator", "Tests\Beh
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VariableCapture", "Tests\Behavioral\VariableCapture\VariableCapture.csproj", "{3FE7E147-27F1-4BA6-8794-3347F41A19A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelectStatement", "Tests\Behavioral\SelectStatement\SelectStatement.csproj", "{8DDF8144-4C32-4F22-BD37-BD560BD14C3B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -264,6 +266,10 @@ Global
{3FE7E147-27F1-4BA6-8794-3347F41A19A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FE7E147-27F1-4BA6-8794-3347F41A19A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FE7E147-27F1-4BA6-8794-3347F41A19A0}.Release|Any CPU.Build.0 = Release|Any CPU
{8DDF8144-4C32-4F22-BD37-BD560BD14C3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8DDF8144-4C32-4F22-BD37-BD560BD14C3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DDF8144-4C32-4F22-BD37-BD560BD14C3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DDF8144-4C32-4F22-BD37-BD560BD14C3B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -310,6 +316,7 @@ Global
{63F33680-54ED-4317-85FF-05A0E9C0D513} = {F5D0C4D5-7217-4572-A76C-AAC5BEF6219B}
{75DF947E-AAFF-4E52-8334-D937C3C1AFE8} = {F5D0C4D5-7217-4572-A76C-AAC5BEF6219B}
{3FE7E147-27F1-4BA6-8794-3347F41A19A0} = {F5D0C4D5-7217-4572-A76C-AAC5BEF6219B}
{8DDF8144-4C32-4F22-BD37-BD560BD14C3B} = {F5D0C4D5-7217-4572-A76C-AAC5BEF6219B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {96A9E85F-A473-4202-B41E-F0E5F3B9AF22}
Expand Down
4 changes: 3 additions & 1 deletion src/go2cs2/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"program": "${fileDirname}",
"args": [
//"-var=false",
//"-uco=false",
//"-tree",
//"..\\Tests\\Behavioral\\SortArrayType\\SortArrayType.go",
//"..\\Tests\\Behavioral\\ArrayPassByValue\\ArrayPassByValue.go",
Expand All @@ -26,7 +27,8 @@
//"..\\Tests\\Behavioral\\RangeStatements",
//"..\\Tests\\Behavioral\\SpreadOperator",
//"..\\Tests\\Behavioral\\VariableCapture",
"..\\Tests\\Behavioral\\TypeSwitch",
//"..\\Tests\\Behavioral\\TypeSwitch",
"..\\Tests\\Behavioral\\SelectStatement",
]
}
]
Expand Down
12 changes: 9 additions & 3 deletions src/go2cs2/ToDo.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@
07) Check implementation of standalone `convStructType` visitor - add test code for when is it encountered - or remove
08) Complete map type implementation (`visitMapType`)
09) ~~Complete type switch implementation (`visitTypeSwitchStmt`) -- see `visitSwitchStmt`~~
10) Complete select statement implementation (`visitSelectStmt`)
11) Complete send statement implementation (`visitSendStmt`)
10) ~~Complete select statement implementation (`visitSelectStmt`)~~ Handle edge cases
a) Handle `case i3, ok := (<-c3): // same as: i3, ok := <-c`
b) Handle `case a[f()] = <-c4: // same as: case t := <-c4 { a[f()] = t }`
c) Handle multi-valued assignment form of (with OK to test for closed channel).
d) Test `nil` channel which is never ready for communication
e) Handle channels with specified direction (send or receive)
11) ~~Complete send statement implementation (`visitSendStmt`)~~
12) Complete struct interfaces and embedding (will need C# GoType code converter work)
13) Complete interface inheritance (will need C# GoType code converter work)
14) Complete channel implementation (`visitChanType` / `visitCommClause`)
14) ~~Complete channel implementation (`visitChanType` / `visitCommClause`)~~
a) Suspected complete through existing paths - add test code for when is it encountered - or remove
15) Handle generics conversion

xx) Setup reference code packages / path options for Go modules
Expand Down
22 changes: 19 additions & 3 deletions src/go2cs2/convCallExpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,27 @@ func (v *Visitor) convCallExpr(callExpr *ast.CallExpr) string {

if typeParam != nil {
if _, ok := typeParam.(*types.Slice); ok {
return fmt.Sprintf("new %s(%s)", typeName, remainingArgs)
if v.options.preferVarDecl {
return fmt.Sprintf("new slice<%s>(%s)", typeName, remainingArgs)
}

return fmt.Sprintf("new(%s)", remainingArgs)
} else if _, ok := typeParam.(*types.Map); ok {
return fmt.Sprintf("new %s(%s)", typeName, remainingArgs)
if v.options.preferVarDecl {
return fmt.Sprintf("new map<%s, %s>", typeName, remainingArgs)
}

return fmt.Sprintf("new(%s)", remainingArgs)
} else if _, ok := typeParam.(*types.Chan); ok {
return fmt.Sprintf("new %s(%s)", typeName, remainingArgs)
if len(remainingArgs) == 0 {
remainingArgs = "1"
}

if v.options.preferVarDecl {
return fmt.Sprintf("new channel<%s>(%s)", typeName, remainingArgs)
}

return fmt.Sprintf("new(%s)", remainingArgs)
}
}

Expand Down
25 changes: 22 additions & 3 deletions src/go2cs2/convSliceExpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"go/ast"
"go/token"
)

func (v *Visitor) convSliceExpr(sliceExpr *ast.SliceExpr) string {
Expand All @@ -15,17 +16,17 @@ func (v *Visitor) convSliceExpr(sliceExpr *ast.SliceExpr) string {

// sliceExpr[Low:] => sliceExpr[Low..]
if sliceExpr.Low != nil && sliceExpr.High == nil && !sliceExpr.Slice3 {
return ident + "[" + v.convExpr(sliceExpr.Low, nil) + "..]"
return ident + "[" + v.getRangeIndexer(sliceExpr.Low) + "..]"
}

// sliceExpr[:High] => sliceExpr[..High]
if sliceExpr.Low == nil && sliceExpr.High != nil && !sliceExpr.Slice3 {
return ident + "[.." + v.convExpr(sliceExpr.High, nil) + "]"
return ident + "[.." + v.getRangeIndexer(sliceExpr.High) + "]"
}

// sliceExpr[Low:High] => sliceExpr[Low..High]
if sliceExpr.Low != nil && sliceExpr.High != nil && !sliceExpr.Slice3 {
return ident + "[" + v.convExpr(sliceExpr.Low, nil) + ".." + v.convExpr(sliceExpr.High, nil) + "]"
return ident + "[" + v.getRangeIndexer(sliceExpr.Low) + ".." + v.getRangeIndexer(sliceExpr.High) + "]"
}

// sliceExpr[:High:Max] => sliceExpr.slice(-1, High, Max)
Expand All @@ -42,3 +43,21 @@ func (v *Visitor) convSliceExpr(sliceExpr *ast.SliceExpr) string {
println(fmt.Sprintf("WARNING: @convSliceEpr - Failed to convert `ast.SliceExpr` format %s", expr))
return fmt.Sprintf("/* %s */", expr)
}

func (v *Visitor) getRangeIndexer(expr ast.Expr) string {
if isIntegerLiteral(expr) {
return v.convExpr(expr, nil)
}

return fmt.Sprintf("(int)(%s)", v.convExpr(expr, nil))
}

func isIntegerLiteral(expr ast.Expr) bool {
if basicLit, ok := expr.(*ast.BasicLit); ok {
if basicLit.Kind == token.INT {
return true
}
}

return false
}
11 changes: 11 additions & 0 deletions src/go2cs2/convUnaryExpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,16 @@ func (v *Visitor) convUnaryExpr(unaryExpr *ast.UnaryExpr) string {
return AddressPrefix + v.convExpr(unaryExpr.X, nil)
}

if unaryExpr.Op == token.ARROW {
// Check if the unary expression is channel receive operation
if _, ok := v.getType(unaryExpr.X, true).(*types.Chan); ok {
if v.options.useChannelOperators {
return fmt.Sprintf("%s(%s)", ChannelLeftOp, v.convExpr(unaryExpr.X, nil))
}

return fmt.Sprintf("%s.Receive()", v.convExpr(unaryExpr.X, nil))
}
}

return unaryExpr.Op.String() + v.convExpr(unaryExpr.X, nil)
}
Loading

0 comments on commit 3d87f14

Please sign in to comment.