diff --git a/helpers/c#/helpers.cs b/helpers/c#/helpers.cs index 3b829cf..3460cd2 100644 --- a/helpers/c#/helpers.cs +++ b/helpers/c#/helpers.cs @@ -912,4 +912,44 @@ public static string Slice(object str2, object idx1, object idx2) return str[start..end]; } } + + public static object arrayConcat(object a, object b) + { + if (a == null && b == null) + { + return null; + } + else if (a == null) + { + return b; + } + else if (b == null) + { + return a; + } + + if (a is IList && b is IList) + { + List result = new List((IList)a); + result.AddRange((IList)b); + return result; + } + else if (a is IList && b is IList) + { + List result = new List((IList)a); + result.AddRange((IList)b); + return result; + } + else if (a is IList> && b is IList>) + { + List> result = new List>((IList>)a); + result.AddRange((IList>)b); + return result; + } + else + { + throw new InvalidOperationException("Unsupported types for concatenation."); + } + } + } \ No newline at end of file diff --git a/helpers/go/helpers.go b/helpers/go/helpers.go index c783842..a2af4ff 100644 --- a/helpers/go/helpers.go +++ b/helpers/go/helpers.go @@ -1231,3 +1231,27 @@ func Remove(dict interface{}, key interface{}) { // Remove the key from the map delete(castedDict, keyStr) } + +func ArrayConcat(first interface{}, second interface{}) interface{} { + // Ensure both arguments are slices + firstValue := reflect.ValueOf(first) + secondValue := reflect.ValueOf(second) + + if firstValue.Kind() != reflect.Slice { + panic("first argument must be a slice") + } + if secondValue.Kind() != reflect.Slice { + panic("second argument must be a slice") + } + + // Check if the slices have the same type + if firstValue.Type() != secondValue.Type() { + panic(fmt.Sprintf("slice types do not match: %s != %s", firstValue.Type(), secondValue.Type())) + } + + // Concatenate the two slices using reflect.AppendSlice + result := reflect.AppendSlice(firstValue, secondValue) + + // Return the concatenated slice as an interface{} + return result.Interface() +} diff --git a/src/baseTranspiler.ts b/src/baseTranspiler.ts index ea342eb..ffe2548 100644 --- a/src/baseTranspiler.ts +++ b/src/baseTranspiler.ts @@ -1097,6 +1097,10 @@ class BaseTranspiler { return undefined; // stub } + printConcatCall(node, identation, name = undefined, parsedArg = undefined) { + return undefined; // stub + } + printToFixedCall(node, identation, name = undefined, parsedArg = undefined) { return undefined; // stub } @@ -1238,6 +1242,8 @@ class BaseTranspiler { return this.printSplitCall(node, identation, name, parsedArg); case 'toFixed': return this.printToFixedCall(node, identation, name, parsedArg); + case 'concat': + return this.printConcatCall(node, identation, name, parsedArg); case 'search': return this.printSearchCall(node, identation, name, parsedArg); case 'endsWith': diff --git a/src/csharpTranspiler.ts b/src/csharpTranspiler.ts index 2054a57..f488625 100644 --- a/src/csharpTranspiler.ts +++ b/src/csharpTranspiler.ts @@ -904,6 +904,10 @@ export class CSharpTranspiler extends BaseTranspiler { return `((string)${name}).Split(new [] {((string)${parsedArg})}, StringSplitOptions.None).ToList()`; } + printConcatCall(node, identation, name = undefined, parsedArg = undefined) { + return `arrayConcat(${name}, ${parsedArg})`; + } + printToFixedCall(node, identation, name = undefined, parsedArg = undefined) { return `toFixed(${name}, ${parsedArg})`; } diff --git a/src/goTranspiler.ts b/src/goTranspiler.ts index b7da215..2cc0a89 100644 --- a/src/goTranspiler.ts +++ b/src/goTranspiler.ts @@ -1032,6 +1032,10 @@ ${this.getIden(identation)}}`; return `ToString(${name})`; } + printConcatCall(node, identation, name = undefined, parsedArg = undefined) { + return `ArrayConcat(${name}, ${parsedArg})`; + } + printToUpperCaseCall(node, identation, name = undefined) { return `ToUpper(${name})`; } diff --git a/src/phpTranspiler.ts b/src/phpTranspiler.ts index 215345d..df0b93f 100644 --- a/src/phpTranspiler.ts +++ b/src/phpTranspiler.ts @@ -268,6 +268,10 @@ export class PhpTranspiler extends BaseTranspiler { return `explode(${parsedArg}, ${name})`; } + printConcatCall(node: any, identation: any, name?: any, parsedArg?: any) { + return `array_merge(${name}, ${parsedArg})`; + } + printPadEndCall(node, identation, name, parsedArg, parsedArg2) { return `str_pad(${name}, ${parsedArg}, ${parsedArg2}, STR_PAD_RIGHT)`; } diff --git a/src/pythonTranspiler.ts b/src/pythonTranspiler.ts index a4f3795..20350c3 100644 --- a/src/pythonTranspiler.ts +++ b/src/pythonTranspiler.ts @@ -143,6 +143,10 @@ export class PythonTranspiler extends BaseTranspiler { return `${name}.split(${parsedArg})`; } + printConcatCall(node: any, identation: any, name?: any, parsedArg?: any) { + return `${name} + ${parsedArg}`; + } + printPopCall(node: any, identation: any, name?: any) { return `${name}.pop()`; } diff --git a/tests/csharpTranspiler.test.ts b/tests/csharpTranspiler.test.ts index 64da926..461a840 100644 --- a/tests/csharpTranspiler.test.ts +++ b/tests/csharpTranspiler.test.ts @@ -929,6 +929,12 @@ describe('csharp transpiling tests', () => { const output = transpiler.transpileCSharp(ts).content; expect(output).toBe(csharp); }); + test('should convert concat', () => { + const ts = "y.concat(z)"; + const result = "arrayConcat(y, z);"; + const output = transpiler.transpileCSharp(ts).content; + expect(output).toBe(result); + }); test('string literal', () => { const ts = "const x = \"foo, 'single', \\\"double\\\" \\t \\n \\r \\b \\f \";"; const csharp = "object x = \"foo, 'single', \\\"double\\\" \\t \\n \\r \\b \\f \";"; diff --git a/tests/goTranspiler.test.ts b/tests/goTranspiler.test.ts index 03475d3..b12f61e 100644 --- a/tests/goTranspiler.test.ts +++ b/tests/goTranspiler.test.ts @@ -126,4 +126,10 @@ describe('go transpiling tests', () => { const output = transpiler.transpileGo(ts).content; expect(output).toBe(go); }); + test('should convert concat', () => { + const ts = "y.concat(z)"; + const result = "ArrayConcat(y, z)"; + const output = transpiler.transpileGo(ts).content; + expect(output).toBe(result); + }); }); diff --git a/tests/integration/cs/TranspilerHelpers.cs b/tests/integration/cs/TranspilerHelpers.cs index b083803..79ad00c 100644 --- a/tests/integration/cs/TranspilerHelpers.cs +++ b/tests/integration/cs/TranspilerHelpers.cs @@ -915,4 +915,43 @@ public static string Slice(object str2, object idx1, object idx2) return str[start..end]; } } + + public static object arrayConcat(object a, object b) + { + if (a == null && b == null) + { + return null; + } + else if (a == null) + { + return b; + } + else if (b == null) + { + return a; + } + + if (a is IList && b is IList) + { + List result = new List((IList)a); + result.AddRange((IList)b); + return result; + } + else if (a is IList && b is IList) + { + List result = new List((IList)a); + result.AddRange((IList)b); + return result; + } + else if (a is IList> && b is IList>) + { + List> result = new List>((IList>)a); + result.AddRange((IList>)b); + return result; + } + else + { + throw new InvalidOperationException("Unsupported types for concatenation."); + } + } } \ No newline at end of file diff --git a/tests/integration/go/helpers.go b/tests/integration/go/helpers.go index 1d9700b..01a4094 100644 --- a/tests/integration/go/helpers.go +++ b/tests/integration/go/helpers.go @@ -1242,3 +1242,28 @@ func Capitalize(s string) string { // Combine the uppercase first letter with the rest of the string return firstLetter + s[1:] } + +// ArrayConcat concatenates two arrays in place. +func ArrayConcat(first interface{}, second interface{}) interface{} { + // Ensure both arguments are slices + firstValue := reflect.ValueOf(first) + secondValue := reflect.ValueOf(second) + + if firstValue.Kind() != reflect.Slice { + panic("first argument must be a slice") + } + if secondValue.Kind() != reflect.Slice { + panic("second argument must be a slice") + } + + // Check if the slices have the same type + if firstValue.Type() != secondValue.Type() { + panic(fmt.Sprintf("slice types do not match: %s != %s", firstValue.Type(), secondValue.Type())) + } + + // Concatenate the two slices using reflect.AppendSlice + result := reflect.AppendSlice(firstValue, secondValue) + + // Return the concatenated slice as an interface{} + return result.Interface() +} diff --git a/tests/integration/source/transpilable.ts b/tests/integration/source/transpilable.ts index 9878bcb..c6973f4 100644 --- a/tests/integration/source/transpilable.ts +++ b/tests/integration/source/transpilable.ts @@ -53,6 +53,11 @@ class Test { console.log(dictKeys.length); // should print 1 console.log(dictKeys[0]); // should print "b" + const firstConcat = ["a", "b"]; + const secondConcat = ["c", "d"]; + const both = firstConcat.concat(secondConcat); + console.log(both.length); // should print 4 + console.log(both[2]); // should print "c" } } diff --git a/tests/phpTranspiler.test.ts b/tests/phpTranspiler.test.ts index 5c35084..65485e1 100644 --- a/tests/phpTranspiler.test.ts +++ b/tests/phpTranspiler.test.ts @@ -861,6 +861,12 @@ describe('php transpiling tests', () => { const output = transpiler.transpilePhp(ts).content; expect(output).toBe(php); }); + test('should convert concat', () => { + const ts = "y.concat(z)"; + const result = "array_merge($y, $z);"; + const output = transpiler.transpilePhp(ts).content; + expect(output).toBe(result); + }); test('string literal', () => { const ts = "const x = \"foo, 'single', \\\"double\\\" \\t \\n \\r \\b \\f \";"; const php = "$x = 'foo, \\\'single\\\', \"double\" \\t \\n \\r \\b \\f ';"; diff --git a/tests/pythonTranspiler.test.ts b/tests/pythonTranspiler.test.ts index e337abd..180672b 100644 --- a/tests/pythonTranspiler.test.ts +++ b/tests/pythonTranspiler.test.ts @@ -786,6 +786,12 @@ describe('python tests', () => { const output = transpiler.transpilePython(ts).content; expect(output).toBe(python); }); + test('should convert concat', () => { + const ts = "y.concat(z)"; + const result = "y + z"; + const output = transpiler.transpilePython(ts).content; + expect(output).toBe(result); + }); test('should convert search', () => { const ts = '"abcdxtzyw".search("xt");'; const python = "'abcdxtzyw'.find('xt')";