Skip to content

Commit 804678b

Browse files
committed
add feature for shipping experimental features
1 parent 81aa038 commit 804678b

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
@@ -4,7 +4,9 @@ use crate::helpers::deserialize::*;
44
use crate::project_context::ProjectContext;
55
use anyhow::{Result, bail};
66
use convert_case::{Case, Casing};
7-
use serde::Deserialize;
7+
use serde::de::{Error as DeError, Visitor};
8+
use serde::{Deserialize, Deserializer};
9+
use std::collections::HashMap;
810
use std::fs;
911
use std::path::{MAIN_SEPARATOR, Path, PathBuf};
1012

@@ -224,6 +226,39 @@ pub enum DeprecationWarning {
224226
BscFlags,
225227
}
226228

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

257292
pub namespace: Option<NamespaceConfig>,
258293
pub jsx: Option<JsxSpecs>,
294+
#[serde(rename = "experimentalFeatures")]
295+
pub experimental_features: Option<HashMap<ExperimentalFeature, bool>>,
259296
#[serde(rename = "gentypeconfig")]
260297
pub gentype_config: Option<GenTypeConfig>,
261298
// this is a new feature of rewatch, and it's not part of the rescript.json spec
@@ -498,6 +535,25 @@ impl Config {
498535
}
499536
}
500537

538+
pub fn get_experimental_features_args(&self) -> Vec<String> {
539+
match &self.experimental_features {
540+
None => vec![],
541+
Some(map) => map
542+
.iter()
543+
.filter_map(|(k, v)| if *v { Some(k) } else { None })
544+
.flat_map(|feature| {
545+
vec![
546+
"-enable-experimental".to_string(),
547+
match feature {
548+
ExperimentalFeature::LetUnwrap => "LetUnwrap",
549+
}
550+
.to_string(),
551+
]
552+
})
553+
.collect(),
554+
}
555+
}
556+
501557
pub fn get_gentype_arg(&self) -> Vec<String> {
502558
match &self.gentype_config {
503559
Some(_) => vec!["-bs-gentype".to_string()],

0 commit comments

Comments
 (0)