This is the latest docs version
Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • Twitter
  • GitHub
  • Forum
Old DocsBS@8.2.0
Interop
  • Overview
  • Better Data Structures Printing (Debug Mode)
  • Miscellaneous
  • Decorators
Advanced
  • Conditional Compilation
    • Usage
    • Built-in & Custom Variables
    • Concrete Syntax
    • Typing Rules
    • Tips & Tricks
  • Extended Compiler Options
  • Compiler Architecture & Principles
  • Comparison to Js_of_ocaml
Docs / Old Docs / ConditionalCompilation
IMPORTANT!
This section is still about ReasonML & BuckleScript. It will be rewritten to ReScript very soon.

Conditional Compilation

This only works with the old OCaml syntax.

Sometimes you want to write code that works with different versions of compilers and libraries.

People used to use preprocessors like C preprocessor for the C family languages. The OCaml community uses several preprocessors: cppo, ocp-pp, camlp4 IFDEF macros, optcomp and ppx optcomp.

Instead of a preprocessor, ReScript adds language-level static if compilation. It's less powerful than other preprocessors since it only supports static if (no #define, #undefine, #include), but there are several advantages.

  • It’s tiny (only ~500 lines) and highly efficient. Everything can be done in a single pass. It's easy to rebuild the pre-processor into a standalone file, with no dependencies on compiler libs, to back-port it to old OCaml compilers.

  • It’s purely functional and type-safe, and cooperates with editor tooling like Merlin.

Usage

lwt_unix.mli

ML
type open_flag = Unix.open_flag = | O_RDONLY | O_WRONLY | O_RDWR | O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_NOCTTY | O_DSYNC | O_SYNC | O_RSYNC #if OCAML_VERSION =~ ">=3.13" then | O_SHARE_DELETE #end #if OCAML_VERSION =~ ">=4.01" then | O_CLOEXEC #end

You don't have to add anything to the build to have these work. The compiler bsc understands these already.

Built-in & Custom Variables

See the output of bsc.exe -bs-list-conditionals:

SH
> bsc.exe -bs-D CUSTOM_A="ghsigh" -bs-list-conditionals OCAML_PATCH "BS" BS_VERSION "1.2.1" OS_TYPE "Unix" BS true CUSTOM_A "ghsigh" WORD_SIZE 64 OCAML_VERSION "4.02.3+BS" BIG_ENDIAN false

Add your custom variable to the mix with -bs-D MY_VAR="bla":

SH
> bsc.exe -bs-D MY_VAR="bla" -bs-list-conditionals OCAML_PATCH "BS" BS_VERSION "1.2.1" OS_TYPE "Unix" BS true MY_VAR="bla" ...

Concrete Syntax

ML
static-if | HASH-IF-BOL conditional-expression THEN // tokens (HASH-ELIF-BOL conditional-expression THEN) * (ELSE-BOL tokens)? HASH-END-BOL conditional-expression | conditional-expression && conditional-expression | conditional-expression || conditional-expression | atom-predicate atom-predicate | atom operator atom | defined UIDENT | undefined UIDENT operator | (= | < | > | <= | >= | =~ ) atom | UIDENT | INT | STRING | FLOAT
  • IF-BOL means #IF should be in the beginning of a line.

Typing Rules

  • type of INT is int

  • type of STRING is string

  • type of FLOAT is float

  • value of UIDENT comes from either built-in values (with documented types) or an environment variable, if it is literally true, false then it is bool, else if it is parsable by Belt.Int.fromString then it is of type int, else if it is parsable by Belt.Float.fromString then it is float, otherwise it would be string

  • In lhs operator rhs, lhs and rhs are always the same type and return boolean. =~ is a semantic version operator which requires both sides to be string.

Evaluation rules are obvious. =~ respect semantic version, for example, the underlying engine

ML
semver Location.none "1.2.3" "~1.3.0" = false;; semver Location.none "1.2.3" "^1.3.0" = true ;; semver Location.none "1.2.3" ">1.3.0" = false ;; semver Location.none "1.2.3" ">=1.3.0" = false ;; semver Location.none "1.2.3" "<1.3.0" = true ;; semver Location.none "1.2.3" "<=1.3.0" = true ;; semver Location.none "1.2.3" "1.2.3" = true;;

Tips & Tricks

This is a very small extension to OCaml. It's backward compatible with OCaml except in the following case:

ML
let f x = x #elif //

#elif at the beginning of a line is interpreted as static if. there is no issue with #if or #end, since they are already keywords.

DecoratorsExtended Compiler Options

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on