The Language Astro

Astro is the first of five languages designed for a compiler course.

1 Introduction

Astro is a fairly trivial programming language with interesting features that make it a great fit for introducing (1) compiler and interpreter writing, and (2) formal language semantics.

This document defines the language Astro.

2 Language Description

2.1 Programs

A programis a sequence of one or more statements. There are only two kinds of statements, assignments and print statements. Comments begin with // and extend to the end of the line.

// A simple program in Astro

radius = 55.2 * (-cos(2.8E-20) + 89) % 21;    // assignment statement
the_area = π * radius ** 2;                   // another assignment
print hypot(2.28, 3 - radius) / the_area;     // print statement

Apologies for the old-fashioned semicolons, but they do make the language somewhat easier to parse.

2.2 Values

All values in Astro are either:

2.3 Types

All values in Astro have a type. Numeric values belong to the type $\textsf{Num}$. Functions of $n$ parameters belong to the type $\textsf{Fun}\,n$.

2.4 Literals

Numeric values in Astro are denoted with literals as in JavaScript:

2
2.0
55.9
819.999e-15
2E+10
5.89999e2

There are no function literals.

2.5 Variables

A variable is a named container for a value. Variables in Astro get their name and initial value through anassignment, which binds an identifier to a variable. There are five built-in variables. All other variables must be assigned to before they can subsequently be used.

sister = 5 + 1;              // variable declaration of sister (Ⅴ + Ⅰ = Ⅵ)
print sister;                // OK: sister has been assigned
// print cousin;             // ERROR: cousin has not been assigned
print π;                     // Turns out to be okay because π is built-in

Variables can be mutable or immutable. All variables bound in the standard library are immutable. All other variables are mutable.

let x = 1;
x = 2;                       // OK: x is mutable
// sqrt = 5;                 // ERROR: sqrt is immutable

Functions can only be called. They cannot be used in a context where a number is expected:

// print sin;                // ERROR
// t = sin;                  // ERROR
// strange = sin * 3         // ERROR

Functions declared with $n$ parameters must be passed exactly $n$ arguments when called.

2.6 Statements

A statement is code that is executed solely for its side effect; it produces no value. The kinds of statements are:

2.7 Expressions

An expression produces a numeric value. For numeric literals $n$, identifiers $i$ and $f$, and expressions $e$, $e_1$, and $e_2$, the Astro expressions are:

3 Standard Library

The following identifiers are pre-defined in a scope that surrounds the program. This means that none of these identifiers may be declared anywhere in a program.

4 Formal Syntax

The source of a Astro program is a Unicode string. Here is the syntax given as an Ohm grammar:

astro.ohm
Astro {
  Program     = Statement+
  Statement   = id "=" Exp ";"                         --assignment
              | print Exp ";"                          --print
  Exp         = Exp ("+" | "-") Term                   --binary
              | Term
  Term        = Term ("*" | "/" | "%") Factor          --binary
              | Factor
  Factor      = Primary "**" Factor                    --binary
              | "-" Primary                            --negation
              | Primary
  Primary     = id "(" ListOf<Exp, ","> ")"            --call
              | numeral                                --num
              | id                                     --id
              | "(" Exp ")"                            --parens

  numeral     = digit+ ("." digit+)? (("E" | "e") ("+" | "-")? digit+)?
  print       = "print" ~idchar
  idchar      = letter | digit | "_"
  id          = ~print letter idchar*
  space      += "//" (~"\n" any)*                      --comment
}

5 Formal Semantics

The meaning of an Astro program is defined in this section via transition rules in the style of Natural Semantics. It is defined from the following abstract syntax:

Abstract Syntax of Astro
$ \begin{array}{lcl} n: \mathsf{Nml} & & \\ i: \mathsf{Ide} & & \\ e: \mathsf{Exp} & = & n \mid i \mid -e \mid e\;o\;e \mid \mathtt{call}\;i\;e^*\\ o: \mathsf{Bop} & = & + \mid - \mid * \mid / \mid \% \mid ** \\ s: \mathsf{Stm} & = & i = e \mid \mathtt{print}\;e\\ p: \mathsf{Pro} & = & \mathtt{program}\;s^+\\ \end{array}$

5.1 Static Semantics

Constructs are statically analyzed relative to a context that keeps track of the type and mutability status of each identifier.

Statically analyzing an expression computes its type; statically analyzing a statement or block computes the resulting context; Statically analyzing a program simply determines whether it satisfies all contextual rules.

Static Semantics of Astro
$$ \frac{}{\mathsf{Num}\!:\mathsf{Type}}$$
$$ \frac{n\!:\mathsf{Nat}}{\mathsf{Fun}\;n\!:\mathsf{Type}}$$
$$ \frac{}{\textsf{ro}\!:\textsf{Access}}$$
$$ \frac{}{\textsf{rw}\!:\textsf{Access}}$$
$\Gamma\!: \mathsf{Context} =_{\textrm{def}}\; \mathsf{Map}\;\mathsf{Identifier}\;(\mathsf{Type} \times \mathsf{Access})$
$$\frac{}{ \Gamma \vdash [\![n]\!]\!: \textsf{Num}}$$
$$\frac{\Gamma(i) = (\textsf{Num}, \_)}{ \Gamma \vdash [\![i]\!]\!: \textsf{Num}}$$
$$\frac{\Gamma \vdash e\!: \textsf{Num}}{ \Gamma \vdash [\![-e]\!]\!: \textsf{Num}}$$
$$\frac{\Gamma \vdash e_1\!: \textsf{Num} \quad \Gamma \vdash e_2\!: \textsf{Num}} { \Gamma \vdash [\![e_1\;o\;e_2]\!]\!: \textsf{Num}}$$
$$\frac{\Gamma(f) = (\textsf{Fun}\;n,\,\_) \quad (\Gamma \vdash e_j\!: \textsf{Num})_{j=1}^n} { \Gamma \vdash [\![\texttt{call}\;f\;e_1,\ldots,e_n]\!]\!: \textsf{Num}}$$
$$\frac{ \Gamma(i) = \bot \lor \Gamma(i) = (\textsf{Num}, \textsf{rw}) \quad \Gamma \vdash e\!: \textsf{Num}} {\Gamma \vdash [\![i=e]\!] \Longrightarrow \Gamma}$$
$$\frac{ \Gamma \vdash e\!: \textsf{Num}} {\Gamma \vdash [\![\texttt{print}\;e]\!] \Longrightarrow \Gamma}$$
$$\frac{(\Gamma_{j-1} \vdash s_j \Longrightarrow \Gamma_{j})_{j=1}^n} { \vdash [\![\mathtt{program}\;s_1,\ldots,s_n]\!]\;\textsf{ok}}$$
$\begin{array}{l} \Gamma_{0} = \{ \\ \quad\texttt{π}\!: (\textsf{Num}, \textsf{ro}), \\ \quad\texttt{sqrt}\!: (\textsf{Fun}\,1, \textsf{ro}), \\ \quad\texttt{sin}\!: (\textsf{Fun}\,1, \textsf{ro}), \\ \quad\texttt{cos}\!: (\textsf{Fun}\,1, \textsf{ro}), \\ \quad\texttt{hypot}\!: (\textsf{Fun}\,2, \textsf{ro}) \\ \} \end{array}$

5.2 Dynamic Semantics

As Astro has no nested scopes and no shadowing, we can never have a scenario in which two variables share the same name. Therefore, dynamic evaluation requires only a global memory mapping identifiers directly to the values stored in the variable bound to the identifier, as well as output tracking.

Dynamic Semantics of Astro
$\begin{array}{l} m\!: \textsf{Mem} = \textsf{Map}\;\textsf{Ide}\;(\textsf{Num} \;\mid\; \textsf{Num}^*\to \textsf{Num}) \\ o\!: \textsf{Output} = \textsf{Num}^* \\ \\ \Downarrow_{\small P} \;\subseteq \mathsf{Pro} \times \mathsf{Output} \\ \Downarrow_{\small S} \;\subseteq (\mathsf{Stm} \times \mathsf{Mem} \times \mathsf{Output}) \times (\mathsf{Mem} \times \mathsf{Output}) \\ \Downarrow_{\small E} \;\subseteq (\mathsf{Exp} \times \mathsf{Mem}) \times \mathsf{Num} \end{array}$
$$ \frac{}{[\![n]\!],m \Downarrow n} $$
$$ \frac{}{[\![i]\!],m \Downarrow m(i)} $$
$$ \frac{e,m \Downarrow x}{[\![\mathsf{-}\;e]\!],m \Downarrow -x} $$
$$ \frac{e_1,m \Downarrow x \quad e_2,m \Downarrow y} {[\![e_1\;op\;e_2]\!],m \Downarrow op(x,y)} $$
$$ \frac{( e_i,m \Downarrow a_i)_{i=1}^n} {[\![\texttt{call}\;i\;e_1,\ldots,e_n]\!],m \Downarrow m(i)(a_1,\ldots,a_n)} $$
$$ \frac{e,m \Downarrow x} {[\![i=e]\!],m,o \Downarrow (m[i \mapsto x], o)} $$
$$ \frac{e,m \Downarrow x} {[\![\mathtt{print}\;e]\!],m,o \Downarrow (m, o\,\mathtt{+\!+}\,[x])} $$
$$ \frac{(s_i,m_{i-1}, o_{i-1} \Downarrow (m_i,o_i))_{i=1}^n} {[\![\mathtt{program}\;s_1,\ldots,s_n]\!] \Downarrow o_n} $$
$\begin{array}{l} o_0 = [\,] \\ m_0 = \{\texttt{π}\mapsto \pi, \texttt{sqrt}\mapsto (\lambda x.\sqrt{x}), \texttt{sin}\mapsto \textrm{sin}, \texttt{cos}\mapsto \textrm{cos}, \texttt{hypot}\mapsto (\lambda (x,y).\sqrt{x^2+y^2})\} \end{array}$