Skip to content

Commit 0d2e0ce

Browse files
committed
add feature for shipping experimental features
1 parent 7a7bc1e commit 0d2e0ce

File tree

14 files changed

+199
-3
lines changed

14 files changed

+199
-3
lines changed

compiler/bsc/rescript_compiler_main.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,10 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
402402
( "-absname",
403403
set absname,
404404
"*internal* Show absolute filenames in error messages" );
405+
( "-enable-experimental",
406+
string_call Experimental_features.enable_from_string,
407+
"Enable experimental features: repeatable, e.g. -enable-experimental \
408+
LetUnwrap" );
405409
(* Not used, the build system did the expansion *)
406410
( "-bs-no-bin-annot",
407411
clear Clflags.binary_annotations,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
type feature = LetUnwrap
2+
3+
let to_string (f : feature) : string =
4+
match f with
5+
| LetUnwrap -> "LetUnwrap"
6+
7+
let from_string (s : string) : feature option =
8+
match s with
9+
| "LetUnwrap" -> Some LetUnwrap
10+
| _ -> None
11+
12+
let enabled_features : feature list ref = ref []
13+
let enable_from_string (s : string) =
14+
match from_string s with
15+
| Some f -> enabled_features := f :: !enabled_features
16+
| None -> ()
17+
18+
let is_enabled (f : feature) = List.mem f !enabled_features
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type feature = LetUnwrap
2+
3+
val enable_from_string : string -> unit
4+
val is_enabled : feature -> bool
5+
val to_string : feature -> string

compiler/frontend/bs_builtin_ppx.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ let expr_mapper ~async_context ~in_function_def (self : mapper)
171171
],
172172
body )
173173
when Ast_attributes.has_unwrap_attr pvb_attributes -> (
174+
if not (Experimental_features.is_enabled Experimental_features.LetUnwrap)
175+
then
176+
Bs_syntaxerr.err pvb_pat.ppat_loc
177+
(Experimental_feature_not_enabled LetUnwrap);
174178
let variant : [`Result_Ok | `Result_Error | `Option_Some | `Option_None] =
175179
match variant_name with
176180
| "Ok" -> `Result_Ok

compiler/frontend/bs_syntaxerr.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type error =
4747
| Misplaced_label_syntax
4848
| Optional_in_uncurried_bs_attribute
4949
| Bs_this_simple_pattern
50+
| Experimental_feature_not_enabled of Experimental_features.feature
5051

5152
let pp_error fmt err =
5253
Format.pp_print_string fmt
@@ -82,7 +83,13 @@ let pp_error fmt err =
8283
each constructor must have an argument."
8384
| Conflict_ffi_attribute str -> "Conflicting attributes: " ^ str
8485
| Bs_this_simple_pattern ->
85-
"%@this expect its pattern variable to be simple form")
86+
"%@this expect its pattern variable to be simple form"
87+
| Experimental_feature_not_enabled feature ->
88+
Printf.sprintf
89+
"Experimental feature not enabled: %s. Enable it by setting \"%s\" to \
90+
true under \"experimentalFeatures\" in rescript.json"
91+
(Experimental_features.to_string feature)
92+
(Experimental_features.to_string feature))
8693

8794
type exn += Error of Location.t * error
8895

compiler/frontend/bs_syntaxerr.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type error =
4747
| Misplaced_label_syntax
4848
| Optional_in_uncurried_bs_attribute
4949
| Bs_this_simple_pattern
50+
| Experimental_feature_not_enabled of Experimental_features.feature
5051

5152
val err : Location.t -> error -> 'a
5253

docs/docson/build-schema.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,17 @@
484484
"editor": {
485485
"$ref": "#/definitions/editor",
486486
"description": "Configure editor functionality, like modules that should be included in autocompletions for given (built-in) types."
487+
},
488+
"experimentalFeatures": {
489+
"type": "object",
490+
"description": "Enable experimental compiler features.",
491+
"properties": {
492+
"LetUnwrap": {
493+
"type": "boolean",
494+
"description": "Enable let? syntax."
495+
}
496+
},
497+
"additionalProperties": false
487498
}
488499
},
489500
"additionalProperties": false,

rewatch/CompilerConfigurationSpec.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This document contains a list of all bsconfig parameters with remarks, and wheth
3232
| bs-external-includes | array of string | | [_] |
3333
| suffix | Suffix | | [x] |
3434
| reanalyze | Reanalyze | | [_] |
35+
| experimentalFeatures | ExperimentalFeatures | | [x] |
3536

3637
### Source
3738

@@ -111,6 +112,17 @@ enum: "classic" | "automatic"
111112

112113
enum: | "dce" | "exception" | "termination"
113114

115+
### ExperimentalFeatures
116+
117+
An object of feature flags to enable experimental compiler behavior. Only supported by Rewatch.
118+
119+
- Keys: feature identifiers (PascalCase)
120+
- Values: boolean (true to enable)
121+
122+
Currently supported features:
123+
124+
- LetUnwrap: Enable the `let?` transformation.
125+
114126
### Warnings
115127

116128
| Parameter | JSON type | Remark | Implemented? |

rewatch/src/build/compile.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ pub fn compiler_args(
381381
let jsx_mode_args = root_config.get_jsx_mode_args();
382382
let jsx_preserve_args = root_config.get_jsx_preserve_args();
383383
let gentype_arg = config.get_gentype_arg();
384+
let experimental_args = root_config.get_experimental_features_args();
384385
let warning_args = config.get_warning_args(is_local_dep);
385386

386387
let read_cmi_args = match has_interface {
@@ -445,6 +446,7 @@ pub fn compiler_args(
445446
bsc_flags.to_owned(),
446447
warning_args,
447448
gentype_arg,
449+
experimental_args,
448450
// vec!["-warn-error".to_string(), "A".to_string()],
449451
// ^^ this one fails for bisect-ppx
450452
// this is the default

rewatch/src/config.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::build::packages;
22
use crate::helpers::deserialize::*;
33
use anyhow::{Result, bail};
44
use convert_case::{Case, Casing};
5-
use serde::Deserialize;
5+
use serde::de::{Error as DeError, Visitor};
6+
use serde::{Deserialize, Deserializer};
7+
use std::collections::HashMap;
68
use std::fs;
79
use std::path::{Path, PathBuf};
810

@@ -222,6 +224,39 @@ pub enum DeprecationWarning {
222224
BscFlags,
223225
}
224226

227+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
228+
pub enum ExperimentalFeature {
229+
LetUnwrap,
230+
}
231+
232+
impl<'de> serde::Deserialize<'de> for ExperimentalFeature {
233+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234+
where
235+
D: Deserializer<'de>,
236+
{
237+
struct EFVisitor;
238+
impl<'de> Visitor<'de> for EFVisitor {
239+
type Value = ExperimentalFeature;
240+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
241+
write!(f, "a valid experimental feature id (e.g. LetUnwrap)")
242+
}
243+
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
244+
where
245+
E: DeError,
246+
{
247+
match v {
248+
"LetUnwrap" => Ok(ExperimentalFeature::LetUnwrap),
249+
other => Err(DeError::custom(format!(
250+
"Unknown experimental feature '{}'. Available features: LetUnwrap",
251+
other
252+
))),
253+
}
254+
}
255+
}
256+
deserializer.deserialize_any(EFVisitor)
257+
}
258+
}
259+
225260
/// # rescript.json representation
226261
/// This is tricky, there is a lot of ambiguity. This is probably incomplete.
227262
#[derive(Deserialize, Debug, Clone, Default)]
@@ -254,6 +289,8 @@ pub struct Config {
254289

255290
pub namespace: Option<NamespaceConfig>,
256291
pub jsx: Option<JsxSpecs>,
292+
#[serde(rename = "experimentalFeatures")]
293+
pub experimental_features: Option<HashMap<ExperimentalFeature, bool>>,
257294
#[serde(rename = "gentypeconfig")]
258295
pub gentype_config: Option<GenTypeConfig>,
259296
// this is a new feature of rewatch, and it's not part of the rescript.json spec
@@ -491,6 +528,25 @@ impl Config {
491528
}
492529
}
493530

531+
pub fn get_experimental_features_args(&self) -> Vec<String> {
532+
match &self.experimental_features {
533+
None => vec![],
534+
Some(map) => map
535+
.iter()
536+
.filter_map(|(k, v)| if *v { Some(k) } else { None })
537+
.flat_map(|feature| {
538+
vec![
539+
"-enable-experimental".to_string(),
540+
match feature {
541+
ExperimentalFeature::LetUnwrap => "LetUnwrap",
542+
}
543+
.to_string(),
544+
]
545+
})
546+
.collect(),
547+
}
548+
}
549+
494550
pub fn get_gentype_arg(&self) -> Vec<String> {
495551
match &self.gentype_config {
496552
Some(_) => vec!["-bs-gentype".to_string()],

0 commit comments

Comments
 (0)