Skip to content

Instantly share code, notes, and snippets.

@koher
Last active February 26, 2017 14:39
Show Gist options
  • Save koher/2a902db3ea840673d44aae4df2b6f07f to your computer and use it in GitHub Desktop.
Save koher/2a902db3ea840673d44aae4df2b6f07f to your computer and use it in GitHub Desktop.
SwiftScript Translation Catalog

SwiftScript Translation Catalog (Draft)

This is a catalog of translations by SwiftScript, a transpiler from Swift to JavaScript, for a hackathon. It supports only a subset of Swift and has some incompatibilities.

Supporting Library

SwiftScript tries to translate Swift codes to JS codes using builtin JS APIs. However some needs a supporting library to simulate behaviors of Swift. A typical example is ?..

If

// Swift
foo?.bar

is translated to

// JavaScript (ES6)
(foo == null ? null : foo.bar)

, it causes a problem when foo is a complex or mutating expression. Introducing a function q (as ?) resolves it.

// JavaScript (ES6)
q(foo, foo => foo.bar)

Declarations

Variables

// Swift
var a: Int? = 42
// JavaScript (ES6)
let a = 42;

Constants

// Swift
let a = 42
// JavaScript (ES6)
const a = 42;

Functions

// Swift
func foo(x: Int, y: String) -> T {
  ...
}
// JavaScript (ES6)
function foo(x, y) {
  ...
}

Classes

Constructors and Properties

// Swift
class Foo {
  var x: Int
  let y: String
  var z: Bool = true

  init(x: Int, y: String) {
    self.x = x
    self.y = y
  }
}
// JavaScript (ES6)
class Foo {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.z = true;
  }
}

Methods

// Swift
class Foo {
  func foo(x: Int, y: String) -> Foo {
    ...
  }
}
// JavaScript (ES6)
class Foo {
  foo(x, y) {
    ...
  }
}

Computed Properties

// Swift
class Foo {
  private var _x: Int = 0
  var x: Int {
    get {
      return self._x
    }
    set {
      print(self.x)
      self._x = newValue
    }
  }
}
// JavaScript (ES6)
class Foo {
  constructor() {
    this._x = 0;
  }

  get x() {
    return this._x;
  }

  set x(newValue) {
    console.log(this.x);
    this._x = newValue;
  }
}

Inheritances

// Swift
class Bar: Foo {
  override init() {
    super.init()
  }

  override func foo(x: Int, y: String) -> Foo {
    ...
  }
}
// JavaScript (ES6)
class Bar extends Foo {
  constructor(x, y) {
    super();
  }

  foo(x, y) {
    ...
  }
}

Static Members

// Swift
class Foo {
  static func foo(x: Int, y: String) -> Foo {
    ...
  }
}
// JavaScript (ES6)
class Foo {
  static foo(x, y) {
    ...
  }
}

Structures struct

Unsupported.

Enumerations enum

Unsupported.

Protocols

// Swift
protocol Foo {
  ...
}
// JavaScript (ES6)

Just ignores protocols. Be aware that protocol names are required in ASTs to distinguish if a type should be contained in extends clause. Only classes should be contained there in JS.

Statements

If Statements

// Swift
if foo {
  ...
} else if bar {
  ...
} else {
  ...
}
// JavaScript (ES6)
if (foo) {
  ...
} else if (bar) {
  ...
} else {
  ...
}

Guard Statements

// Swift
guard foo else {
  ...
}
// JavaScript (ES6)
if (!(foo)) {
  ...
}

Switch Statements

// Swift
switch foo {
  case 1:
    ...
  case 2:
    ...
    return
  case 3:
    break
  case 4:
    ...
    fallthrough
  default:
    ...
}
// JavaScript (ES6)
switch (foo) {
  case 1:
    ...
    break;
  case 2:
    ...
    return;
  case 3:
    break;
  case 4:
    ...
  default:
    ...
    break;
}

With Pattern Matchings

Unsupported.

While Statements

// Swift
while foo {
  ...
}
// JavaScript (ES6)
while (foo) {
  ...
}

Repeat-while Statements

// Swift
repeat {
  ...
} while foo
// JavaScript (ES6)
do {
  ...
} while (foo);

For-in Statements

// Swift
for foo in foos {
  ...
}
// JavaScript (ES6)
for (foo of foos) {
  ...
}

With a range

Ranges
// Swift
for i in 0..<42 {
  ...
}
// JavaScript (ES6)
for (let i = 0; i < 42; i++) {
  ...
}
Closed Ranges
// Swift
for i in 0...42 {
  ...
}
// JavaScript (ES6)
for (let i = 0; i < 43; i++) {
  ...
}

Do Statements

// Swift
do {
  ...
}
// JavaScript (ES6)
{
  ...
}

Return Statements

// Swift
return foo
// JavaScript (ES6)
return foo;

Break Statements

// Swift
break
// JavaScript (ES6)
break;

Continue Statements

// Swift
continue
// JavaScript (ES6)
continue;

Do-catch Statements

// Swift
do {
  ...
} catch let error {
  ...
}
// JavaScript (ES6)
try {
  ...
} catch (error) {
  ...
}

With multiple catches

// Swift
do {
  ...
} catch let error as FooError {
  ...
} catch let error as BarError {
  ...
} catch let error {
  ...
}
// JavaScript (ES6)
try {
  ...
} catch (error) {
  if (error instanceof FooError) {
    ...
  } else if (error instanceof BarError) {
    ...
  } else {
    ...
  }
}

Throw Statements

// Swift
throw foo
// JavaScript (ES6)
throw foo;

Defer Statements

Unsupported.

Expressions

Closure Expressions

// Swift
{ (x: Int, y: String) -> Foo in
  ...
  return ...
}
// JavaScript (ES6)
(x, y) => {
  ...
  return ...;
}

With a single expression

// Swift
{ (x: Int, y: String) -> Foo in foo(x) }
// JavaScript (ES6)
(x, y) => foo(x)

With a single argument

// Swift
{ (x: Int) -> Foo in
  ...
  return ...
}
// JavaScript (ES6)
x => {
  ...
  return ...;
}

With anonymous arguments

// Swift
{ foo($0, $1) }
// JavaScript (ES6)
($0, $1) => foo($0, $1)

$0, $1 and so on are valid identifiers in JS.

Function calls

// Swift
foo(bar: 42, baz: "xyz")
// JavaScript (ES6)
foo(42, "xyz")

Labels are just ignored in JS.

Initializer calls

// Swift
Foo(x: 42, y: "xyz")
// JavaScript (ES6)
new Foo(42, "xyz")

Trailing Closures

// Swift
foo(x) { a, b in bar(a, b) }
foo { a, b in bar(a, b) }
// JavaScript (ES6)
foo(x, (a, b) => foo(a, b))
foo((a, b) => foo(a, b))

Subscripts

Basically common in both languages.

// Swift
foo[bar]
// JavaScript (ES6)
foo[bar]

Subscripts for custom types are not supported.

self

// Swift
self
// JavaScript (ES6)
this

()

Common in both languages.

// Swift
(foo)
// JavaScript (ES6)
(foo)

Tuples

// Swift
(2, 3, 5)
// JavaScript (ES6)
[2, 3, 5];

Assignment

// Swift
let (x, y, z) = (2, 3, 5)
// JavaScript (ES6)
const [x, y, z] = [2, 3, 5];

Implicit member expressions

// Swift
.some(42)

Unsupported.

Wildcard Expressions

// Swift
_

Unsupported.

Although _ is a valid identifier in JS, redeclaring _ causes a syntax error.

?.

// Swift
foo?.bar
// JavaScript (ES6)
q(foo, foo => foo.bar)

q is a function in the supporting library.

try

// Swift
try foo()
// JavaScript (ES6)
foo()

try!

// Swift
try! foo()
// JavaScript (ES6)
tryx(() => foo())

tryx is a function in the supporting library.

try?

// Swift
try? foo()
// JavaScript (ES6)
tryq(() => foo())

tryq is a function in the supporting library.

Operators

Binary Operators

Most operators are common in both languages. This subsection lists up only operators which needs some translations.

??

// Swift
foo ?? bar
// JavaScript (ES6)
qq(foo, bar)

qq is a function in the supporting library.

is

// Swift
foo is Foo
// JavaScript (ES6)
foo instanceof Foo

as

// Swift
foo as Foo
// JavaScript (ES6)
foo

as?

// Swift
foo as Foo
// JavaScript (ES6)
asq(foo, foo => foo instanceof Foo)

asq is a function in the supporting library.

as!

// Swift
foo as Foo
// JavaScript (ES6)
asx(foo, foo => foo instanceof Foo)

asx is a function in the supporting library.

..., ..<

// Swift
1...10
0..<10
// JavaScript (ES6)
range(1, 11)
range(0, 10)

range is a function in the supporting library, which should be implemented function* and yield (References: function*, range implementation by legacy generator function).

Precedences

Because it does not support precedencegroup and custom operators for the present, precedences of operators follow ones of Swift 2.

References: Swift 2, JavaScript

Swift

Precedence Operators
160 <<, >>, *, /, %, &
140 +, -, `
135 ..., ..<
132 is, as, as?, as!
131 ??
130 <, <=, >, >=, ==, !=, ===, !==
120 &&
110 `
100 ?:
90 =, +=, -=, *=, /=, %=, <<=, >>=, &=, `

JavaScript

Precedence Operators
14 *, /, %
13 +, -
12 <<, >>
11 <, <=, >, >=, instanceof
10 ==, !=, ===, !==
9 &
8 ^
7 `
6 &&
5 `
4 ?:
3 =, +=, -=, *=, /=, %=, <<=, >>=, &=, `
<<, >>, &, |, ^, instanceof

Some operators have a lower precedence in JS than in Swift. They should be used in (). It is also possible to use all operators in () to simulate those precedences perfectly. However it results redundant ()s like ((2 + 3) + 5) for 2 + 3 + 5. To prevent those redundant ()s, we add an extra () for only <<, >>, &, |, ^, instanceof.

// Swift
foo << bar
// JavaScript (ES6)
(foo << bar)
==, !=, ===, !==

Although their precedences in JS are slightly different from ones in Swift, they seems not to cause problems in most cases. Combinations of operators like < and ones like == appear rarely.

Unary Operators

Prefix +, -, ! and ~ are common in both languages. This subsection lists up only operators which needs some translations.

Postfix !

// Swift
foo!
// JavaScript (ES6)
x(foo)

x is a function in the supporting library.

Ternary Operator ?:

It is common in both languages.

Operator Functions

Unsupported.

Custom Operators

Unsupported.

Literals

Does not support ExpressibleBy*. Then most literals in both languages are common.

// Swift
123
123.0
true
false
// JavaScript (ES6)
123
123.0
true
false

nil

// Swift
nil
// JavaScript (ES6)
null

Strictly speaking, they are not equivalent because null cannot be nested. Int?? in Swift can distinguish .none or .some(.none) while null in JS cannot.

In this hackathon, we do not support such behaviors of Optionals in Swift.

Strings

String literals are basically common in both languages.

// Swift
"xyz"
// JavaScript (ES6)
"xyz"

Special Characters

Special characters in string literals are basically common in both languages.

References: Swift, JavaScript

String Interpolations

// Swift
"xyz\(foo)"
// JavaScript (ES6)
`xyz${foo}`

Arrays

// Swift
[foo, bar, baz]
// JavaScript (ES6)
[foo, bar, baz]

Strictly speaking, they are not equivalent because Array is a value type in Swift and a reference type in JS.

In this hackathon, we ignores such a difference.

Dictionaries

// Swift
[
  "foo": 2,
  "bar": 3,
  "baz": 5
]
// JavaScript (ES6)
{
  "foo": 2,
  "bar": 3,
  "baz": 5
}

Strictly speaking, they are not equivalent because Dictionary in Swift is a value type and Object in JS is a reference type. Object in JS also does not support key types except String.

In this hackathon, we ignores such a difference.

Others

Generics

Just ignores inside <>.

Functions

// Swift
func foo<T: Sequence, U>(_ x: T) -> U where T.Iterator.Element == Int, U: Equatable {
  ...
}
// JavaScript (ES6)
function foo(x) {
  ...
}

Types

// Swift
class Foo<T: Sequence, U> where T.Iterator.Element == Int, U: Equatable {
  ...
}
// JavaScript (ES6)
class Foo {
  ...
}

Call sites

// Swift
foo<Bar<Baz>>(bar)
// JavaScript (ES6)
foo(bar)

Overloads

Unsupported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment