Language Syntax

goose has a minimal syntax that aims to be highly readable. In this section, we'll cover the syntax rules and conventions of the goose language in-depth.

If you're new to goose, we recommend starting with the Language Tour to get a quick overview of the language.

Syntax Rules

goose classifies code into statements and expressions. A statement can be thought of an action, while an expression represents a usable value. For example, let x = 5 is a statement that assigns the value 5 to the variable x, while 5 + 5 is an expression that evaluates to 10.

Statements can only be written in certain contexts, like the top-level of a file or inside a function. Expressions, however, can be written almost anywhere, including where statements are expected.

goose
// statement context
let x = 5

x // expression as statement

if /* expression context */ x > 0
  // new statement context
end

if let y = x + 5 // invalid statement where expression is expected
  println(y)
end

Statements don't need to be separated by a semicolon or any other delimiter. In fact, statements don't even need to be on separate lines! The parser can work out where one statement ends and another begins based on the syntax rules of the language. However, it is recommended to use new lines to separate statements for readability.

goose
// completely valid! but not recommended
let x = 5 let y = 10 println(x + y)

// equivalent to:
let x = 5
let y = 10
println(x + y)

Inside blocks, whitespace isn't significant either, but indenting each level by 2 spaces is recommended for readability and clarity.

goose
if x > 5
println("x is greater than 5")
end

// equivalent to:
if x > 5
  println("x is greater than 5")
end

Comments

goose supports both single-line and multi-line comments. Single-line comments start with // and continue until the end of the line. Multi-line comments start with /* and end with */. Multi-line comments cannot be nested.

goose
// this is a single-line comment

/*
  This is a multi-line comment
  that spans multiple lines
*/

Identifiers

Identifiers are used to name variables, functions, and other entities in goose. An identifier must start with a letter or an underscore and can contain letters, numbers, and underscores. Identifiers are case-sensitive. By convention, identifiers should be written in snake_case.

More formally, all valid identifiers must match the regular expression [a-zA-Z_][a-zA-Z0-9_]*.

goose
let my_variable = 5
fn hello_world()
  println("Hello, World!")
end

// invalid identifiers
let 1variable = 5 // cannot start with a number
let my-variable = 5 // cannot contain hyphens
let $varia@ble = 5 // cannot contain special characters (except underscore)

Keywords

goose has a set of reserved keywords that cannot be used as identifiers. These keywords are used to define the structure of the language and cannot be redefined or shadowed.

The following is a list of all the keywords in goose:

let       const     symbol    if      then    else
repeat    while     forever   times   for     in
break     continue  fn        end     return  memo
import    export    as        show    is      generator
yield     to        step      struct  init    operator
try       catch     finally   throw   do      async
await     native    match     when    frozen