OJaml / docsProject documentation

Reference

Surface Language

Look up syntax, contracts, layouts, algorithms, and exact behavior.

An OJaml program is a sequence of top-level let declarations, module type declarations, module declarations, top-level open declarations, record type declarations, and algebraic data type declarations with optional type parameters. A let declaration may be recursive, may bind parameters, may annotate those parameters, may carry a value annotation, and may be separated by optional double semicolons. Module declarations contain value bindings, nested modules, record types, and algebraic data types; module members are reached through qualified names such as Scores.total, Scores.Offsets.make, Geometry.point, or Geometry.Named, and open Geometry exposes immediate values, types, and constructors by short name when no local, top-level, or competing opened namespace owns that name. Module type declarations contain abstract type entries, concrete record or variant type manifests, and val signatures. Module ascription checks that an implementation exports every promised type and value at the declared type, and concrete manifests must match the implementation's field or constructor structure. Expressions include primitives, tuples, tuple projection, records, field access, variables, unary and binary operations, sequencing, forward pipelines, conditionals, local lets, local function bindings, local recursive function bindings, function application, anonymous functions, constructor application, and match expressions.

let main =
  println "Hello, OJaml!"
Hello world. A minimal program binds main to an expression. println accepts int, float, or string, writes a trailing newline, and returns unit.
P::=D∗D::=let  rec?  x  q∗(:τ)?=e∣module type  S=sig  V∗  end∣module  M(:S)?=struct  D∗  end∣type  ...∣open  MP ::= D^{*}\quad\quad D ::= \texttt{let}\;\texttt{rec?}\;x\;q^{*}(\texttt{:}\tau)?=e\mid\texttt{module type}\;S=\texttt{sig}\;V^{*}\;\texttt{end}\mid\texttt{module}\;M(\texttt{:}S)?=\texttt{struct}\;D^{*}\;\texttt{end}\mid\texttt{type}\;...\mid\texttt{open}\;M
Program grammar. A program is a list of declarations; modules group values, types, and nested modules under qualified names, module types specify required abstract types and values, and open declarations expose namespace members by short name.

The surface syntax borrows the OCaml forms that support this compiler's goals without committing to the whole language. Function application is whitespace-based. Parentheses group expressions and represent unit when empty. Sequencing uses expr; expr, requires the left expression to return unit, and returns the right expression's type. Forward pipelines use value |> f and typecheck as f value, so the target must be a one-argument function after any ordinary application on the right has run. Structural records use { field = value; other = value } syntax, record type declarations use type person = { name: string; year: int }, algebraic data type declarations use type status = Pending | Done of int and type 'a option = None | Some of 'a, value annotations use let ada : person = ... or let value : int option = ..., parameter annotations use let describe (person : person) = ..., higher-order annotations use forms such as let apply (f : int -> int) = ..., and field access uses value.field. Comments are block comments with nesting support. Module-style names such as Map.get or Scores.total are lexed as identifiers, and open List or open Scores exposes values by short name; user modules also expose immediate type names and constructors by short name.

open List
open String

let main =
  let words = split (concat "hello" " OJaml") " " in
  String.length (head words) + List.length words
Opening stdlib namespaces. Opened stdlib namespaces provide short names, while exact local or top-level names win and ambiguous names still require a qualified form.
let rec fact n =
  match n with
  | 0 -> 1
  | 1 -> 1
  | _ -> n * fact (n - 1)

let main =
  let x = fact 5 in
  if x > 100 then x else 0
Core expression tour. Top-level recursion, match, local let, arithmetic, comparison, and if/then/else all compile through the same expression checker.
d::=type  x={x:τ;…}∣let  rec?  x  x∗  (:τ)?=ee::=n∣f∣s∣b∣()∣(e,e+)∣{x=e;…}∣e.x∣e.k∣x∣e  e+∣fun  x+→e∣let  rec?  x  x∗  (:τ)?=e  in  e∣if  e  then  e  else  e∣match  e  with  (p→e)+d ::= \texttt{type}\;x=\{x:\tau;\ldots\}\mid \texttt{let}\;\texttt{rec?}\;x\;x^{*}\;(:\tau)?=e\\ e ::= n\mid f\mid s\mid b\mid ()\mid (e, e^{+})\mid \{x=e;\ldots\}\mid e.x\mid e.k\mid x\mid e\;e^{+}\mid \texttt{fun}\;x^{+}\rightarrow e\mid \texttt{let}\;\texttt{rec?}\;x\;x^{*}\;(:\tau)?=e\;\texttt{in}\;e\mid \texttt{if}\;e\;\texttt{then}\;e\;\texttt{else}\;e\mid \texttt{match}\;e\;\texttt{with}\;(p\rightarrow e)^{+}
Expression grammar. Local function parameters are parsed into anonymous functions; local rec is restricted to function bindings so the compiler can build a self-referential closure.

Every construct in the grammar maps to a direct AST node. That correspondence is an engineering choice: it keeps diagnostics precise, lets hover spans point back to real tokens, and lets later compilation passes switch on explicit node kinds instead of recovering meaning from parser artifacts.

  • Lexed token kinds include ints, floats, strings, identifiers, keywords, operators, parentheses, braces, pipes, arrows, equals, separators, and EOF.
  • Supported primitive values are int, float, bool, string, and unit; tuple expressions group values by position, zero-based postfix projection reads tuple elements, record type declarations name record shapes, algebraic data type declarations name constructor sets and type parameters, structural records group values by label, and fst/snd remain pair-specific helpers.
  • Supported binary operators include int and float arithmetic, right-associative power **, mixed numeric comparisons, equality/inequality, short-circuit boolean conjunction/disjunction, int-only mod, and forward pipeline |>.
  • Patterns cover int, float, string, bool, unit, tuple structure, record structure, list structure, fixed-length array structure, set structure, map structure, constructor structure, wildcard, and variable catch-all patterns.