Skip to content

Language Reference

This page contains a language reference with a complete overview of all language syntax available in hop.

Types

There are eight built-in types available in hop.

Bool

The Bool type represents booleans.

Boolean literals are constructed via the keywords true and false.

OperationReturns
!BoolBool
Bool && BoolBool
Bool || BoolBool
Bool != BoolBool
Bool == BoolBool

Int

The Int type represents a 64-bit signed integer.

Integer literals are constructed by writing a literal number without a decimal point.

OperationReturns
-IntInt
Int + IntInt
Int - IntInt
Int < IntBool
Int > IntBool
Int <= IntBool
Int >= IntBool
Int == IntBool
Int != IntBool
Int.to_float()Float
Int.to_string()String

Float

The Float type represents a 64-bit floating point number.

Floating point literals are constructed by writing a literal number containing a decimal point.

OperationReturns
-FloatFloat
Float + FloatFloat
Float - FloatFloat
Float < FloatBool
Float > FloatBool
Float <= FloatBool
Float >= FloatBool
Float == FloatBool
Float != FloatBool
Float.to_int()Int
Float.to_string()String

String

The String type represents a string of characters.

String literals are constructed by writing a string using "" as delimiters.

OperationReturns
String + StringString
String == StringBool
String != StringBool
String.is_empty()Bool

Array

The Array type represents an array of a given type.

OperationReturns
Array.len()Int
Array.is_empty()Bool

Option

The Option type represents a container that either holds a value or not.

OperationReturns
Option.is_some()Bool
Option.is_none()Bool

Record

The Record types represent a collection of named fields.

hop
record User {
  name: String,
}

view Main {
  <let {
    user: User = User {name: "Tobi"},
  }>
    The name of the user is {user.name}
  </let>
}
Open in playground

Enum

The Enum types represent a value that can hold exactly one value of a given set of types.

hop
enum LaundryRoomState {
  Free,
  Occupied {
    available_at: String,
  },
}

view Main {
  <let {state: LaundryRoomState = LaundryRoomState::Free}>
    <match {state}>
      <case {LaundryRoomState::Free}>
        <p>
          The laundry room is available.
        </p>
        <button>
          Book now
        </button>
      </case>
      <case {LaundryRoomState::Occupied {available_at}}>
        <p>
          The laundry room is occupied.
        </p>
        <p>
          It becomes available at {available_at}.
        </p>
      </case>
    </match>
  </let>
}
Open in playground

Expressions

Apart from the methods and operators available on values there is only one type of primitive expression available in hop. The match expression.

match

The match expression in hop is similar to the match expression in Rust and is used to destructure a value into different cases.

The match expression works on the Bool, Option and Enum type. Support for matching on other types is in progress.

hop
record User {
  name: String,
  email: String,
}

enum Visibility {
  Visible,
  Hidden,
}

view Main {
  <!-- Matching on Enum -->
  <let {input: Visibility = Visibility::Visible}>
    {match input {
      Visibility::Visible => "It is visible",
      Visibility::Hidden => "It is invisible",
    }}
  </let>
  <!-- Matching on Option -->
  <let {
    current_user: Option[User] = Some(
      User {name: "Loki", email: "loki@example.com"}
    ),
  }>
    {match current_user {
      Some(User {
        name,
        email: _,
      }) => "The current user is " + name,
      None => "There is no current user",
    }}
  </let>
}
Open in playground

Macros

join!

The join! macro concatenates strings, adding a space between each string while filtering out empty strings. The idiomatic use case for the macro is to split long class strings into separate strings.

hop
view Main {
  <div class={
    join!(
      "px-2",
      "py-3",
      "border",
    )
  }>
  </div>
}
Open in playground

asset!

The asset! macro registers an asset and returns the string for its production url.

hop
view Main {
  <div>
    <img src={asset!("/tutorial/2012_2017.jpg")}>
  </div>
}
Open in playground

Tags

<let>

The <let> tag binds one or more variables to the value of the given expression.

hop
view Main {
  <let {
    x: Int = 20,
    y: Int = 5,
    result: String = (x + y).to_string(),
  }>
    The result is {result}
  </let>
}
Open in playground

<match>

The <match> tag is the cousin of the match expression. The <match> tag works just like the match expression but can be used when the purpose of matching is not to produce a value, but instead render different markup depending on which case is matched.

hop
component LoggedInContent {
  <div>
    Welcome to the area for authenticated users.
  </div>
}

component MustSignInMessage {
  <div>
    You need to sign in to view this content.
  </div>
}

view Main {
  <let {logged_in: Bool = true}>
    <match {logged_in}>
      <case {true}>
        <LoggedInContent/>
      </case>
      <case {false}>
        <MustSignInMessage/>
      </case>
    </match>
  </let>
}
Open in playground

<for>

The <for> tag loops over the items of an array, rendering its contents once for each item of the array.

hop
view Main {
  <for {x in ["foo", "bar", "baz"]}>
    <div>
      {x}
    </div>
  </for>
}
Open in playground

<if>

The <if> tag renders its contents when a given condition evaluates to true. It is a shorthand for a match tag on a Bool with an empty false case.

hop
view Main {
  <let {x: Int = 5, y: Int = 10}>
    <if {x + y == 15}>
      <div>
        the math is mathing
      </div>
    </if>
  </let>
}
Open in playground