diff --git a/.depend b/.depend index b93a69e6..3e5cc17a 100644 --- a/.depend +++ b/.depend @@ -12,9 +12,10 @@ src/res_comment.cmx : src/res_comment.cmi src/res_comment.cmi : src/res_comments_table.cmx : src/res_parsetree_viewer.cmx src/res_doc.cmx \ src/res_comment.cmx -src/res_core.cmx : src/res_token.cmx src/res_scanner.cmx src/res_printer.cmx \ - src/res_parser.cmx src/res_js_ffi.cmx src/res_grammar.cmx src/res_doc.cmx \ - src/res_diagnostics.cmx src/res_comments_table.cmx src/res_core.cmi +src/res_core.cmx : src/res_utf8.cmx src/res_token.cmx src/res_scanner.cmx \ + src/res_printer.cmx src/res_parser.cmx src/res_js_ffi.cmx \ + src/res_grammar.cmx src/res_doc.cmx src/res_diagnostics.cmx \ + src/res_comments_table.cmx src/res_core.cmi src/res_core.cmi : src/res_parser.cmi src/res_diagnostics.cmx : src/res_token.cmx src/res_grammar.cmx \ src/res_diagnostics_printing_utils.cmx src/res_diagnostics.cmi @@ -60,16 +61,19 @@ src/res_parser.cmi : src/res_token.cmx src/res_scanner.cmi \ src/res_comment.cmi src/res_parsetree_viewer.cmx : src/res_parsetree_viewer.cmi src/res_parsetree_viewer.cmi : -src/res_printer.cmx : src/res_token.cmx src/res_parsetree_viewer.cmx \ - src/res_parens.cmx src/res_doc.cmx src/res_comments_table.cmx \ - src/res_comment.cmx src/res_printer.cmi +src/res_printer.cmx : src/res_utf8.cmx src/res_token.cmx \ + src/res_parsetree_viewer.cmx src/res_parens.cmx src/res_doc.cmx \ + src/res_comments_table.cmx src/res_comment.cmx src/res_printer.cmi src/res_printer.cmi : src/res_doc.cmi src/res_comments_table.cmx \ src/res_comment.cmi src/res_reporting.cmx : src/res_token.cmx src/res_grammar.cmx -src/res_scanner.cmx : src/res_token.cmx src/res_diagnostics.cmx \ - src/res_comment.cmx src/res_scanner.cmi +src/res_scanner.cmx : src/res_utf8.cmx src/res_token.cmx \ + src/res_diagnostics.cmx src/res_comment.cmx src/res_scanner.cmi src/res_scanner.cmi : src/res_token.cmx src/res_diagnostics.cmi src/res_token.cmx : src/res_comment.cmx -tests/res_test.cmx : src/res_token.cmx src/res_parser.cmx \ - src/res_outcome_printer.cmx src/res_multi_printer.cmx src/res_io.cmx \ - src/res_driver.cmx src/res_core.cmx +src/res_utf8.cmx : src/res_utf8.cmi +src/res_utf8.cmi : +tests/res_test.cmx : tests/res_utf8_test.cmx src/res_token.cmx \ + src/res_parser.cmx src/res_outcome_printer.cmx src/res_multi_printer.cmx \ + src/res_io.cmx src/res_driver.cmx src/res_core.cmx +tests/res_utf8_test.cmx : src/res_utf8.cmx diff --git a/Makefile b/Makefile index ba0ac79c..5480e4a8 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ API_FILES = \ src/res_parsetree_viewer.cmx\ src/res_parens.cmx\ src/res_comments_table.cmx\ + src/res_utf8.cmx\ src/res_printer.cmx\ src/res_scanner.cmx\ src/res_js_ffi.cmx\ @@ -40,7 +41,7 @@ API_FILES = \ CLI_FILES = $(API_FILES) src/res_cli.cmx -TEST_FILES = $(API_FILES) tests/res_test.cmx +TEST_FILES = $(API_FILES) tests/res_utf8_test.cmx tests/res_test.cmx .DEFAULT_GOAL := build-native @@ -74,7 +75,7 @@ test: reanalyze build-native lib/test.exe ./lib/test.exe ./test.sh -roundtrip-test: reanalyze bootstrap lib/test.exe +roundtrip-test: reanalyze lib/test.exe ./lib/test.exe ROUNDTRIP_TEST=1 ./test.sh diff --git a/benchmarks/Benchmark.ml b/benchmarks/Benchmark.ml index 3700403a..6727cc64 100644 --- a/benchmarks/Benchmark.ml +++ b/benchmarks/Benchmark.ml @@ -6,7 +6,6 @@ module Printer = Res_printer module IO: sig val readFile: string -> string - val readStdin: unit -> string end = struct (* random chunk size: 2^15, TODO: why do we guess randomly? *) let chunkSize = 32768 @@ -26,21 +25,6 @@ end = struct ) in loop () - - let readStdin () = - let buffer = Buffer.create chunkSize in - let chunk = (Bytes.create [@doesNotRaise]) chunkSize in - let rec loop () = - let len = try input stdin chunk 0 chunkSize with Invalid_argument _ -> 0 in - if len == 0 then ( - close_in_noerr stdin; - Buffer.contents buffer - ) else ( - Buffer.add_subbytes buffer chunk 0 len; - loop () - ) - in - loop () end module Time: sig @@ -188,29 +172,6 @@ end = struct done end -module Profile: sig - val record : name:string -> (unit -> 'a) -> 'a - val print: unit -> unit -end = struct - let state = Hashtbl.create 2 - - let record ~name f = - let startTime = Time.now() in - let result = f() in - let endTime = Time.now() in - - Hashtbl.add state name (Time.diff startTime endTime); - result - - let print () = - let report = Hashtbl.fold (fun k v acc -> - let line = Printf.sprintf "%s: %fms\n" k (Time.print v) in - acc ^ line - ) state "\n\n" - in - print_endline report -end - module Benchmarks: sig val run: unit -> unit end = struct diff --git a/src/res_ast_conversion.ml b/src/res_ast_conversion.ml index 20eba5ff..39a2029e 100644 --- a/src/res_ast_conversion.ml +++ b/src/res_ast_conversion.ml @@ -323,6 +323,8 @@ let hasUncurriedAttribute attrs = List.exists (fun attr -> match attr with | _ -> false ) attrs +let templateLiteralAttr = (Location.mknoloc "res.template", Parsetree.PStr []) + let normalize = let open Ast_mapper in { default_mapper with @@ -368,7 +370,7 @@ let normalize = in let s = Parsetree.Pconst_string ((escapeTemplateLiteral txt), newTag) in {p with - ppat_attributes = mapper.attributes mapper p.ppat_attributes; + ppat_attributes = templateLiteralAttr::(mapper.attributes mapper p.ppat_attributes); ppat_desc = Ppat_constant s } | _ -> @@ -396,7 +398,7 @@ let normalize = in let s = Parsetree.Pconst_string ((escapeTemplateLiteral txt), newTag) in {expr with - pexp_attributes = mapper.attributes mapper expr.pexp_attributes; + pexp_attributes= templateLiteralAttr::(mapper.attributes mapper expr.pexp_attributes); pexp_desc = Pexp_constant s } | Pexp_apply ( diff --git a/src/res_ast_debugger.ml b/src/res_ast_debugger.ml index 1dbb2d42..212ad106 100644 --- a/src/res_ast_debugger.ml +++ b/src/res_ast_debugger.ml @@ -143,10 +143,13 @@ module SexpAst = struct string txt; optChar tag; ] - | Pconst_char c -> + | Pconst_char _ -> + Sexp.list [ + Sexp.atom "Pconst_char"; + ] + | Pconst_string(_, Some "INTERNAL_RES_CHAR_CONTENTS") -> Sexp.list [ Sexp.atom "Pconst_char"; - Sexp.atom (Char.escaped c); ] | Pconst_string (txt, tag) -> Sexp.list [ diff --git a/src/res_cli.ml b/src/res_cli.ml index e5917bc5..fd92ed00 100644 --- a/src/res_cli.ml +++ b/src/res_cli.ml @@ -165,6 +165,7 @@ module ResClflags: sig val file: string ref val interface: bool ref val ppx: string ref + val typechecker: bool ref val parse: unit -> unit end = struct @@ -176,6 +177,7 @@ end = struct let interface = ref false let ppx = ref "" let file = ref "" + let typechecker = ref false let usage = "\n**This command line is for the repo developer's testing purpose only. DO NOT use it in production**!\n\n" ^ "Usage:\n rescript \n\n" ^ @@ -192,6 +194,7 @@ end = struct ("-width", Arg.Int (fun w -> width := w), "Specify the line length for the printer (formatter)"); ("-interface", Arg.Unit (fun () -> interface := true), "Parse as interface"); ("-ppx", Arg.String (fun txt -> ppx := txt), "Apply a specific built-in ppx before parsing, none or jsx. Default: none"); + ("-typechecker", Arg.Unit (fun () -> typechecker := true), "Parses the ast as it would be passed to the typechecker and not the printer") ] let parse () = Arg.parse spec (fun f -> file := f) usage @@ -200,7 +203,7 @@ end module CliArgProcessor = struct type backend = Parser: ('diagnostics) Res_driver.parsingEngine -> backend [@@unboxed] - let processFile ~isInterface ~width ~recover ~origin ~target ~ppx filename = + let processFile ~isInterface ~width ~recover ~origin ~target ~ppx ~typechecker filename = let len = String.length filename in let processInterface = isInterface || len > 0 && (String.get [@doesNotRaise]) filename (len - 1) = 'i' @@ -233,7 +236,7 @@ module CliArgProcessor = struct in let forPrinter = match target with - | "res" | "sexp" -> true + | "res" | "sexp" when not typechecker -> true | _ -> false in @@ -292,5 +295,6 @@ let [@raises Invalid_argument, Failure, exit] () = ~target:!ResClflags.print ~origin:!ResClflags.origin ~ppx:!ResClflags.ppx + ~typechecker:!ResClflags.typechecker !ResClflags.file end diff --git a/src/res_core.ml b/src/res_core.ml index 94022348..413d3115 100644 --- a/src/res_core.ml +++ b/src/res_core.ml @@ -136,6 +136,7 @@ let ternaryAttr = (Location.mknoloc "ns.ternary", Parsetree.PStr []) let ifLetAttr = (Location.mknoloc "ns.iflet", Parsetree.PStr []) let suppressFragileMatchWarningAttr = (Location.mknoloc "warning", Parsetree.PStr [Ast_helper.Str.eval (Ast_helper.Exp.constant (Pconst_string ("-4", None)))]) let makeBracesAttr loc = (Location.mkloc "ns.braces" loc, Parsetree.PStr []) +let templateLiteralAttr = (Location.mknoloc "res.template", Parsetree.PStr []) type stringLiteralState = | Start @@ -143,6 +144,9 @@ type stringLiteralState = | HexEscape | DecimalEscape | OctalEscape + | UnicodeEscape + | UnicodeCodePointEscape + | UnicodeEscapeStart | EscapedLineBreak type typDefOrExt = @@ -482,15 +486,12 @@ let processUnderscoreApplication args = in (args, wrap) -let hexValue x = - match x with - | '0' .. '9' -> - (Char.code x) - 48 - | 'A' .. 'Z' -> - (Char.code x) - 55 - | 'a' .. 'z' -> - (Char.code x) - 97 - | _ -> 16 +let hexValue ch = + match ch with + | '0'..'9' -> (Char.code ch) - 48 + | 'a'..'f' -> (Char.code ch) - (Char.code 'a') + 10 + | 'A'..'F' -> (Char.code ch) + 32 - (Char.code 'a') + 10 + | _ -> 16 (* larger than any legal value *) let parseStringLiteral s = let len = String.length s in @@ -499,7 +500,7 @@ let parseStringLiteral s = let rec parse state i d = if i = len then (match state with - | HexEscape | DecimalEscape | OctalEscape -> false + | HexEscape | DecimalEscape | OctalEscape | UnicodeEscape | UnicodeCodePointEscape -> false | _ -> true) else let c = String.unsafe_get s i in @@ -517,6 +518,7 @@ let parseStringLiteral s = | ('\\' | ' ' | '\'' | '"') as c -> Buffer.add_char b c; parse Start (i + 1) d | 'x' -> parse HexEscape (i + 1) 0 | 'o' -> parse OctalEscape (i + 1) 0 + | 'u' -> parse UnicodeEscapeStart (i + 1) 0 | '0' .. '9' -> parse DecimalEscape i 0 | '\010' | '\013' -> parse EscapedLineBreak (i + 1) d | c -> Buffer.add_char b '\\'; Buffer.add_char b c; parse Start (i + 1) d) @@ -558,6 +560,45 @@ let parseStringLiteral s = ) else parse OctalEscape (i + 1) (d + 1) + | UnicodeEscapeStart -> + (match c with + | '{' -> parse UnicodeCodePointEscape (i + 1) 0 + | _ -> parse UnicodeEscape (i + 1) 1) + | UnicodeEscape -> + if d == 3 then + let c0 = String.unsafe_get s (i - 3) in + let c1 = String.unsafe_get s (i - 2) in + let c2 = String.unsafe_get s (i - 1) in + let c3 = String.unsafe_get s i in + let c = (4096 * (hexValue c0)) + (256 * (hexValue c1)) + (16 * (hexValue c2)) + (hexValue c3) in + if Res_utf8.isValidCodePoint c then ( + let codePoint = Res_utf8.encodeCodePoint c in + Buffer.add_string b codePoint; + parse Start (i + 1) 0 + ) else ( + false + ) + else + parse UnicodeEscape (i + 1) (d + 1) + | UnicodeCodePointEscape -> + (match c with + | '0'..'9' | 'a'..'f' | 'A'.. 'F' -> + parse UnicodeCodePointEscape (i + 1) (d + 1) + | '}' -> + let x = ref 0 in + for remaining = d downto 1 do + let ix = i - remaining in + x := (!x * 16) + (hexValue (String.unsafe_get s ix)); + done; + let c = !x in + if Res_utf8.isValidCodePoint c then ( + let codePoint = Res_utf8.encodeCodePoint !x in + Buffer.add_string b codePoint; + parse Start (i + 1) 0 + ) else ( + false + ) + | _ -> false) | EscapedLineBreak -> (match c with | ' ' | '\t' -> parse EscapedLineBreak (i + 1) d @@ -871,13 +912,18 @@ let parseConstant p = let floatTxt = if isNegative then "-" ^ f else f in Parsetree.Pconst_float (floatTxt, suffix) | String s -> - let txt = if p.mode = ParseForTypeChecker then - parseStringLiteral s + if p.mode = ParseForTypeChecker then + Pconst_string (s, Some "js") else - s - in - Pconst_string(txt, None) - | Character c -> Pconst_char c + Pconst_string (s, None) + | Codepoint {c; original} -> + if p.mode = ParseForTypeChecker then + Pconst_char c + else + (* Pconst_char char does not have enough information for formatting. + * When parsing for the printer, we encode the char contents as a string + * with a special prefix. *) + Pconst_string (original, Some "INTERNAL_RES_CHAR_CONTENTS") | token -> Parser.err p (Diagnostics.unexpected token p.breadcrumbs); Pconst_string("", None) @@ -1069,7 +1115,7 @@ let rec parsePattern ?(alias=true) ?(or_=true) p = let loc = mkLoc startPos endPos in Ast_helper.Pat.construct ~loc (Location.mkloc (Longident.Lident (Token.toString token)) loc) None - | Int _ | String _ | Float _ | Character _ | Minus | Plus -> + | Int _ | String _ | Float _ | Codepoint _ | Minus | Plus -> let c = parseConstant p in begin match p.token with | DotDot -> @@ -1081,7 +1127,7 @@ let rec parsePattern ?(alias=true) ?(or_=true) p = end | Backtick -> let constant = parseTemplateConstant ~prefix:(Some "js") p in - Ast_helper.Pat.constant ~loc:(mkLoc startPos p.prevEndPos) constant + Ast_helper.Pat.constant ~attrs:[templateLiteralAttr] ~loc:(mkLoc startPos p.prevEndPos) constant | Lparen -> Parser.next p; begin match p.token with @@ -1814,7 +1860,7 @@ and parseAtomicExpr p = let loc = mkLoc startPos p.prevEndPos in Ast_helper.Exp.construct ~loc (Location.mkloc (Longident.Lident (Token.toString token)) loc) None - | Int _ | String _ | Float _ | Character _ -> + | Int _ | String _ | Float _ | Codepoint _ -> let c = parseConstant p in let loc = mkLoc startPos p.prevEndPos in Ast_helper.Exp.constant ~loc c @@ -2181,25 +2227,19 @@ and parseTemplateExpr ?(prefix="js") p = | TemplateTail txt -> Parser.next p; let loc = mkLoc startPos p.prevEndPos in - if String.length txt > 0 then - let txt = if p.mode = ParseForTypeChecker then parseTemplateStringLiteral txt else txt in - let str = Ast_helper.Exp.constant ~loc (Pconst_string(txt, Some prefix)) in - Ast_helper.Exp.apply ~loc hiddenOperator - [Nolabel, acc; Nolabel, str] - else - acc + let txt = if p.mode = ParseForTypeChecker then parseTemplateStringLiteral txt else txt in + let str = Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc (Pconst_string(txt, Some prefix)) in + Ast_helper.Exp.apply ~attrs:[templateLiteralAttr] ~loc hiddenOperator + [Nolabel, acc; Nolabel, str] | TemplatePart txt -> Parser.next p; let loc = mkLoc startPos p.prevEndPos in let expr = parseExprBlock p in let fullLoc = mkLoc startPos p.prevEndPos in let txt = if p.mode = ParseForTypeChecker then parseTemplateStringLiteral txt else txt in - let str = Ast_helper.Exp.constant ~loc (Pconst_string(txt, Some prefix)) in + let str = Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc (Pconst_string(txt, Some prefix)) in let next = - let a = if String.length txt > 0 then - Ast_helper.Exp.apply ~loc:fullLoc hiddenOperator [Nolabel, acc; Nolabel, str] - else acc - in + let a = Ast_helper.Exp.apply ~attrs:[templateLiteralAttr] ~loc:fullLoc hiddenOperator [Nolabel, acc; Nolabel, str] in Ast_helper.Exp.apply ~loc:fullLoc hiddenOperator [Nolabel, a; Nolabel, expr] in @@ -2214,19 +2254,16 @@ and parseTemplateExpr ?(prefix="js") p = | TemplateTail txt -> Parser.next p; let txt = if p.mode = ParseForTypeChecker then parseTemplateStringLiteral txt else txt in - Ast_helper.Exp.constant ~loc:(mkLoc startPos p.prevEndPos) (Pconst_string(txt, Some prefix)) + Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc:(mkLoc startPos p.prevEndPos) (Pconst_string(txt, Some prefix)) | TemplatePart txt -> Parser.next p; let constantLoc = mkLoc startPos p.prevEndPos in let expr = parseExprBlock p in let fullLoc = mkLoc startPos p.prevEndPos in let txt = if p.mode = ParseForTypeChecker then parseTemplateStringLiteral txt else txt in - let str = Ast_helper.Exp.constant ~loc:constantLoc (Pconst_string(txt, Some prefix)) in + let str = Ast_helper.Exp.constant ~attrs:[templateLiteralAttr] ~loc:constantLoc (Pconst_string(txt, Some prefix)) in let next = - if String.length txt > 0 then - Ast_helper.Exp.apply ~loc:fullLoc hiddenOperator [Nolabel, str; Nolabel, expr] - else - expr + Ast_helper.Exp.apply ~attrs:[templateLiteralAttr] ~loc:fullLoc hiddenOperator [Nolabel, str; Nolabel, expr] in parseParts next | token -> diff --git a/src/res_grammar.ml b/src/res_grammar.ml index 394bdd96..ac649a1e 100644 --- a/src/res_grammar.ml +++ b/src/res_grammar.ml @@ -134,7 +134,7 @@ let isSignatureItemStart = function | _ -> false let isAtomicPatternStart = function - | Token.Int _ | String _ | Character _ | Backtick + | Token.Int _ | String _ | Codepoint _ | Backtick | Lparen | Lbracket | Lbrace | Underscore | Lident _ | Uident _ | List @@ -144,7 +144,7 @@ let isAtomicPatternStart = function let isAtomicExprStart = function | Token.True | False - | Int _ | String _ | Float _ | Character _ + | Int _ | String _ | Float _ | Codepoint _ | Backtick | Uident _ | Lident _ | Hash | Lparen @@ -165,7 +165,7 @@ let isAtomicTypExprStart = function let isExprStart = function | Token.True | False - | Int _ | String _ | Float _ | Character _ | Backtick + | Int _ | String _ | Float _ | Codepoint _ | Backtick | Underscore (* _ => doThings() *) | Uident _ | Lident _ | Hash | Lparen | List | Module | Lbracket | Lbrace @@ -194,7 +194,7 @@ let isStructureItemStart = function | _ -> false let isPatternStart = function - | Token.Int _ | Float _ | String _ | Character _ | Backtick | True | False | Minus | Plus + | Token.Int _ | Float _ | String _ | Codepoint _ | Backtick | True | False | Minus | Plus | Lparen | Lbracket | Lbrace | List | Underscore | Lident _ | Uident _ | Hash @@ -301,7 +301,7 @@ let isJsxChildStart = isAtomicExprStart let isBlockExprStart = function | Token.At | Hash | Percent | Minus | MinusDot | Plus | PlusDot | Bang - | True | False | Float _ | Int _ | String _ | Character _ | Lident _ | Uident _ + | True | False | Float _ | Int _ | String _ | Codepoint _ | Lident _ | Uident _ | Lparen | List | Lbracket | Lbrace | Forwardslash | Assert | Lazy | If | For | While | Switch | Open | Module | Exception | Let | LessThan | Backtick | Try | Underscore -> true diff --git a/src/res_parsetree_viewer.ml b/src/res_parsetree_viewer.ml index 7c25e3aa..3bb2da3d 100644 --- a/src/res_parsetree_viewer.ml +++ b/src/res_parsetree_viewer.ml @@ -153,7 +153,7 @@ let processBracesAttr expr = let filterParsingAttrs attrs = List.filter (fun attr -> match attr with - | ({Location.txt = ("ns.ternary" | "ns.braces" | "bs" | "ns.iflet" | "ns.namedArgLoc")}, _) -> false + | ({Location.txt = ("ns.ternary" | "ns.braces" | "res.template" | "bs" | "ns.iflet" | "ns.namedArgLoc")}, _) -> false | _ -> true ) attrs @@ -292,7 +292,7 @@ let isIfLetExpr expr = match expr with let hasAttributes attrs = List.exists (fun attr -> match attr with - | ({Location.txt = "bs" | "ns.ternary" | "ns.braces" | "ns.iflet"}, _) -> false + | ({Location.txt = "bs" | "res.template" | "ns.ternary" | "ns.braces" | "ns.iflet"}, _) -> false (* Remove the fragile pattern warning for iflet expressions *) | ({Location.txt="warning"}, PStr [{ pstr_desc = Pstr_eval ({ @@ -453,13 +453,13 @@ let shouldInlineRhsBinaryExpr rhs = match rhs.pexp_desc with let filterPrinteableAttributes attrs = List.filter (fun attr -> match attr with - | ({Location.txt="bs" | "ns.ternary" | "ns.iflet" | "JSX"}, _) -> false + | ({Location.txt="bs" | "res.template" | "ns.ternary" | "ns.iflet" | "JSX"}, _) -> false | _ -> true ) attrs let partitionPrinteableAttributes attrs = List.partition (fun attr -> match attr with - | ({Location.txt="bs" | "ns.ternary" | "ns.iflet" | "JSX"}, _) -> false + | ({Location.txt="bs" | "res.template"| "ns.ternary" | "ns.iflet" | "JSX"}, _) -> false | _ -> true ) attrs @@ -511,17 +511,19 @@ let rec collectPatternsFromListConstruct acc pattern = collectPatternsFromListConstruct (pat::acc) rest | _ -> List.rev acc, pattern -(* Simple heuristic to detect template literal sugar: - * `${user.name} lastName` parses internally as user.name ++ ` lastName`. - * The thing is: the ++ operator (parsed as `^`) will always have a ghost loc. - * A ghost loc is only produced by our parser. - * Hence, if we have that ghost operator, we know for sure it's a template literal. *) + +let hasTemplateLiteralAttr attrs = List.exists (fun attr -> match attr with +| ({Location.txt = "res.template"}, _) -> true +| _ -> false) attrs + let isTemplateLiteral expr = match expr.pexp_desc with | Pexp_apply ( - {pexp_desc = Pexp_ident {txt = Longident.Lident "^"; loc}}, + {pexp_desc = Pexp_ident {txt = Longident.Lident "^"}}, [Nolabel, _; Nolabel, _] - ) when loc.loc_ghost -> true + ) when hasTemplateLiteralAttr expr.pexp_attributes -> true + | Pexp_constant (Pconst_string (_, Some "")) -> true + | Pexp_constant _ when hasTemplateLiteralAttr expr.pexp_attributes -> true | _ -> false (* Blue | Red | Green -> [Blue; Red; Green] *) diff --git a/src/res_parsetree_viewer.mli b/src/res_parsetree_viewer.mli index f83ea02f..65a67367 100644 --- a/src/res_parsetree_viewer.mli +++ b/src/res_parsetree_viewer.mli @@ -109,6 +109,7 @@ val collectPatternsFromListConstruct: val isBlockExpr : Parsetree.expression -> bool val isTemplateLiteral: Parsetree.expression -> bool +val hasTemplateLiteralAttr: Parsetree.attributes -> bool val collectOrPatternChain: Parsetree.pattern -> Parsetree.pattern list diff --git a/src/res_printer.ml b/src/res_printer.ml index edd92d32..42d2de77 100644 --- a/src/res_printer.ml +++ b/src/res_printer.ml @@ -495,7 +495,7 @@ let printStringContents txt = let lines = String.split_on_char '\n' txt in Doc.join ~sep:Doc.literalLine (List.map Doc.text lines) -let printConstant c = match c with +let printConstant ?(templateLiteral=false) c = match c with | Parsetree.Pconst_integer (s, suffix) -> begin match suffix with | Some c -> Doc.text (s ^ (Char.escaped c)) @@ -508,14 +508,35 @@ let printConstant c = match c with Doc.text "\""; ] | Pconst_string (txt, Some prefix) -> - Doc.concat [ - if prefix = "js" then Doc.nil else Doc.text prefix; - Doc.text "`"; - printStringContents txt; - Doc.text "`"; - ] + if prefix = "INTERNAL_RES_CHAR_CONTENTS" then + Doc.concat [Doc.text "'"; Doc.text txt; Doc.text "'"] + else + let (lquote, rquote) = + if templateLiteral then ("`", "`") else ("\"", "\"") + in + Doc.concat [ + if prefix = "js" then Doc.nil else Doc.text prefix; + Doc.text lquote; + printStringContents txt; + Doc.text rquote; + ] | Pconst_float (s, _) -> Doc.text s - | Pconst_char c -> Doc.text ("'" ^ (Char.escaped c) ^ "'") + | Pconst_char c -> + let str = match c with + | '\'' -> "\\'" + | '\\' -> "\\\\" + | '\n' -> "\\n" + | '\t' -> "\\t" + | '\r' -> "\\r" + | '\b' -> "\\b" + | ' ' .. '~' as c -> + let s = (Bytes.create [@doesNotRaise]) 1 in + Bytes.unsafe_set s 0 c; + Bytes.unsafe_to_string s + | c -> + Res_utf8.encodeCodePoint (Obj.magic c) + in + Doc.text ("'" ^ str ^ "'") let rec printStructure (s : Parsetree.structure) t = match s with @@ -2079,7 +2100,9 @@ and printPattern (p : Parsetree.pattern) cmtTbl = let patternWithoutAttributes = match p.ppat_desc with | Ppat_any -> Doc.text "_" | Ppat_var var -> printIdentLike var.txt - | Ppat_constant c -> printConstant c + | Ppat_constant c -> + let templateLiteral = ParsetreeViewer.hasTemplateLiteralAttr p.ppat_attributes in + printConstant ~templateLiteral c | Ppat_tuple patterns -> Doc.group( Doc.concat([ @@ -2522,7 +2545,8 @@ and printIfChain pexp_attributes ifs elseExpr cmtTbl = and printExpression (e : Parsetree.expression) cmtTbl = let printedExpression = match e.pexp_desc with - | Parsetree.Pexp_constant c -> printConstant c + | Parsetree.Pexp_constant c -> + printConstant ~templateLiteral:(ParsetreeViewer.isTemplateLiteral e) c | Pexp_construct _ when ParsetreeViewer.hasJsxAttribute e.pexp_attributes -> printJsxFragment e cmtTbl | Pexp_construct ({txt = Longident.Lident "()"}, _) -> Doc.text "()" diff --git a/src/res_scanner.ml b/src/res_scanner.ml index b6855f6c..f0180517 100644 --- a/src/res_scanner.ml +++ b/src/res_scanner.ml @@ -319,9 +319,9 @@ let scanStringEscapeSequence ~startPos scanner = loop (n - 1) (x * base + d) in let x = loop n 0 in - if x > max then + if x > max || 0xD800 <= x && x < 0xE000 then let pos = position scanner in - let msg = "invalid escape sequence (value too high)" in + let msg = "escape sequence is invalid unicode code point" in scanner.err ~startPos ~endPos:pos (Diagnostics.message msg) in match scanner.ch with @@ -339,6 +339,24 @@ let scanStringEscapeSequence ~startPos scanner = (* hex *) next scanner; scan ~n:2 ~base:16 ~max:255 + | 'u' -> + next scanner; + (match scanner.ch with + | '{' -> + (* unicode code point escape sequence: '\u{7A}', one or more hex digits *) + next scanner; + let x = ref 0 in + while match scanner.ch with | '0'..'9' | 'a'..'f' | 'A'..'F' -> true | _ -> false do + x := (!x * 16) + (digitValue scanner.ch); + next scanner + done; + (* consume '}' in '\u{7A}' *) + (match scanner.ch with + | '}' -> next scanner + | _ -> ()); + | _ -> + scan ~n:4 ~base:16 ~max:Res_utf8.max + ) | _ -> (* unknown escape sequence * TODO: we should warn the user here. Let's not make it a hard error for now, for reason compat *) @@ -381,6 +399,8 @@ let scanString scanner = Token.String (scan ()) let scanEscape scanner = + (* '\' consumed *) + let offset = scanner.offset - 1 in let convertNumber scanner ~n ~base = let x = ref 0 in for _ = n downto 1 do @@ -388,10 +408,13 @@ let scanEscape scanner = x := (!x * base) + d; next scanner done; - (Char.chr [@doesNotRaise]) !x + let c = !x in + if Res_utf8.isValidCodePoint c then + Char.unsafe_chr c + else + Char.unsafe_chr Res_utf8.repl in - (* let offset = scanner.offset in *) - let c = match scanner.ch with + let codepoint = match scanner.ch with | '0'..'9' -> convertNumber scanner ~n:3 ~base:10 | 'b' -> next scanner; '\008' | 'n' -> next scanner; '\010' @@ -399,11 +422,36 @@ let scanEscape scanner = | 't' -> next scanner; '\009' | 'x' -> next scanner; convertNumber scanner ~n:2 ~base:16 | 'o' -> next scanner; convertNumber scanner ~n:3 ~base:8 + | 'u' -> + next scanner; + begin match scanner.ch with + | '{' -> + (* unicode code point escape sequence: '\u{7A}', one or more hex digits *) + next scanner; + let x = ref 0 in + while match scanner.ch with | '0'..'9' | 'a'..'f' | 'A'..'F' -> true | _ -> false do + x := (!x * 16) + (digitValue scanner.ch); + next scanner + done; + (* consume '}' in '\u{7A}' *) + (match scanner.ch with + | '}' -> next scanner + | _ -> ()); + let c = !x in + if Res_utf8.isValidCodePoint c then + Char.unsafe_chr c + else + Char.unsafe_chr Res_utf8.repl + | _ -> + (* unicode escape sequence: '\u007A', exactly 4 hex digits *) + convertNumber scanner ~n:4 ~base:16 + end | ch -> next scanner; ch in + let contents = (String.sub [@doesNotRaise]) scanner.src offset (scanner.offset - offset) in next scanner; (* Consume \' *) (* TODO: do we know it's \' ? *) - Token.Character c + Token.Codepoint {c = codepoint; original = contents} let scanSingleLineComment scanner = let startOff = scanner.offset in @@ -613,8 +661,26 @@ let rec scan scanner = then relying on matching on the quote *) next scanner; SingleQuote | '\\', _ -> next2 scanner; scanEscape scanner - | ch, '\'' -> next3 scanner; Token.Character ch - | _ -> next scanner; SingleQuote) + | ch, '\'' -> + let offset = scanner.offset + 1 in + next3 scanner; + Token.Codepoint {c = ch; original = (String.sub [@doesNotRaise]) scanner.src offset 1} + | ch, _ -> + next scanner; + let offset = scanner.offset in + let (codepoint, length) = Res_utf8.decodeCodePoint scanner.offset scanner.src (String.length scanner.src) in + for _ = 0 to length - 1 do + next scanner + done; + if scanner.ch = '\'' then ( + let contents = (String.sub [@doesNotRaise]) scanner.src offset length in + next scanner; + Token.Codepoint {c = Obj.magic codepoint; original = contents} + ) else ( + scanner.ch <- ch; + scanner.offset <- offset; + SingleQuote + )) | '!' -> (match peek scanner, peek2 scanner with | '=', '=' -> next3 scanner; Token.BangEqualEqual diff --git a/src/res_token.ml b/src/res_token.ml index a14491dd..b901276a 100644 --- a/src/res_token.ml +++ b/src/res_token.ml @@ -3,7 +3,7 @@ module Comment = Res_comment type t = | Open | True | False - | Character of char + | Codepoint of {c: char; original: string} | Int of {i: string; suffix: char option} | Float of {f: string; suffix: char option} | String of string @@ -88,7 +88,7 @@ let precedence = function let toString = function | Open -> "open" | True -> "true" | False -> "false" - | Character c -> "character '" ^ (Char.escaped c) ^ "'" + | Codepoint {original} -> "codepoint '" ^ original ^ "'" | String s -> "string \"" ^ s ^ "\"" | Lident str -> str | Uident str -> str diff --git a/src/res_utf8.ml b/src/res_utf8.ml new file mode 100644 index 00000000..a8fd99ee --- /dev/null +++ b/src/res_utf8.ml @@ -0,0 +1,141 @@ +(* https://tools.ietf.org/html/rfc3629#section-10 *) +(* let bom = 0xFEFF *) + +let repl = 0xFFFD + +(* let min = 0x0000 *) +let max = 0x10FFFF + +let surrogateMin = 0xD800 +let surrogateMax = 0xDFFF + +(* + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+--------------------------------------------- + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + *) +let h2 = 0b1100_0000 +let h3 = 0b1110_0000 +let h4 = 0b1111_0000 + +let cont_mask = 0b0011_1111 + +type category = { + low: int; + high: int; + size: int; +} + +let locb = 0b1000_0000 +let hicb = 0b1011_1111 + +let categoryTable = [| +(* 0 *) {low = -1; high= -1; size= 1}; (* invalid *) +(* 1 *) {low = 1; high= -1; size= 1}; (* ascii *) +(* 2 *) {low = locb; high= hicb; size= 2}; +(* 3 *) {low = 0xA0; high= hicb; size= 3}; +(* 4 *) {low = locb; high= hicb; size= 3}; +(* 5 *) {low = locb; high= 0x9F; size= 3}; +(* 6 *) {low = 0x90; high= hicb; size= 4}; +(* 7 *) {low = locb; high= hicb; size= 4}; +(* 8 *) {low = locb; high= 0x8F; size= 4}; + +|] + +let categories = [| + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + 1; 1; 1; 1; 1; 1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1 ;1; + + 0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0; + 0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0; + 0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0; + 0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0;0; 0; 0; 0; + (* surrogate range U+D800 - U+DFFFF = 55296 - 917503 *) + 0; 0; 2; 2;2; 2; 2; 2;2; 2; 2; 2;2; 2; 2; 2; + 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; + 3; 4; 4; 4; 4; 4; 4; 4; 4; 4; 4; 4; 4; 5; 4; 4; + 6; 7; 7 ;7; 8; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; +|] + +let decodeCodePoint i s len = + if len < 1 then (repl, 1) else + let first = int_of_char (String.unsafe_get s i) in + if first < 128 then (first, 1) else + let index = Array.unsafe_get categories first in + if index = 0 then + (repl, 1) + else + let cat = Array.unsafe_get categoryTable index in + if len < i + cat.size then + (repl, 1) + else if cat.size == 2 then + let c1 = int_of_char (String.unsafe_get s (i + 1)) in + if c1 < cat.low || cat.high < c1 then + (repl, 1) + else + let i1 = c1 land 0b00111111 in + let i0 = (first land 0b00011111) lsl 6 in + let uc = i0 lor i1 in + (uc, 2) + else if cat.size == 3 then + let c1 = int_of_char (String.unsafe_get s (i + 1)) in + let c2 = int_of_char (String.unsafe_get s (i + 2)) in + if c1 < cat.low || cat.high < c1 || c2 < locb || hicb < c2 then (repl, 1) + else + let i0 = (first land 0b00001111) lsl 12 in + let i1 = (c1 land 0b00111111) lsl 6 in + let i2 = (c2 land 0b00111111) in + let uc = i0 lor i1 lor i2 in + (uc, 3) + else + let c1 = int_of_char (String.unsafe_get s (i +1)) in + let c2 = int_of_char (String.unsafe_get s (i +2)) in + let c3 = int_of_char (String.unsafe_get s (i +3)) in + if c1 < cat.low || cat.high < c1 || + c2 < locb || hicb < c2 || c3 < locb || hicb < c3 + then (repl, 1) + else + let i1 = (c1 land 0x3f) lsl 12 in + let i2 = (c2 land 0x3f) lsl 6 in + let i3 = (c3 land 0x3f) in + let i0 = (first land 0x07) lsl 18 in + let uc = i0 lor i3 lor i2 lor i1 in + (uc, 4) + +let encodeCodePoint c = + if c <= 127 then ( + let bytes = (Bytes.create [@doesNotRaise]) 1 in + Bytes.unsafe_set bytes 0 (Char.unsafe_chr c); + Bytes.unsafe_to_string bytes + ) else if c <= 2047 then ( + let bytes = (Bytes.create [@doesNotRaise]) 2 in + Bytes.unsafe_set bytes 0 (Char.unsafe_chr (h2 lor (c lsr 6))); + Bytes.unsafe_set bytes 1 (Char.unsafe_chr (0b1000_0000 lor (c land cont_mask))); + Bytes.unsafe_to_string bytes + ) else if c <= 65535 then ( + let bytes = (Bytes.create [@doesNotRaise]) 3 in + Bytes.unsafe_set bytes 0 (Char.unsafe_chr (h3 lor (c lsr 12))); + Bytes.unsafe_set bytes 1 (Char.unsafe_chr (0b1000_0000 lor ((c lsr 6) land cont_mask))); + Bytes.unsafe_set bytes 2 (Char.unsafe_chr (0b1000_0000 lor (c land cont_mask))); + Bytes.unsafe_to_string bytes + ) else (* if c <= max then *) ( + let bytes = (Bytes.create [@doesNotRaise]) 4 in + Bytes.unsafe_set bytes 0 (Char.unsafe_chr (h4 lor (c lsr 18))); + Bytes.unsafe_set bytes 1 (Char.unsafe_chr (0b1000_0000 lor ((c lsr 12) land cont_mask))); + Bytes.unsafe_set bytes 2 (Char.unsafe_chr (0b1000_0000 lor ((c lsr 6) land cont_mask))); + Bytes.unsafe_set bytes 3 (Char.unsafe_chr (0b1000_0000 lor (c land cont_mask))); + Bytes.unsafe_to_string bytes + ) + +let isValidCodePoint c = + 0 <= c && c < surrogateMin || surrogateMax < c && c <= max diff --git a/src/res_utf8.mli b/src/res_utf8.mli new file mode 100644 index 00000000..4b7462a4 --- /dev/null +++ b/src/res_utf8.mli @@ -0,0 +1,9 @@ +val repl: int + +val max: int + +val decodeCodePoint: int -> string -> int -> int * int + +val encodeCodePoint: int -> string + +val isValidCodePoint: int -> bool diff --git a/tests/conversion/reason/expected/bracedJsx.re.txt b/tests/conversion/reason/expected/bracedJsx.re.txt index 0cbb8f47..27f93d34 100644 --- a/tests/conversion/reason/expected/bracedJsx.re.txt +++ b/tests/conversion/reason/expected/bracedJsx.re.txt @@ -114,7 +114,7 @@ let make = () => { ref={containerRef->ReactDOMRe.Ref.domRef}> {state.history ->Array.mapWithIndex((index, item) => -
+
{ReasonReact.string( switch item { | User(value) => userPrefix ++ value diff --git a/tests/parsing/errors/expressions/expected/ambiguousArrow.res.txt b/tests/parsing/errors/expressions/expected/ambiguousArrow.res.txt index 4d9c2c4d..596fad0f 100644 --- a/tests/parsing/errors/expressions/expected/ambiguousArrow.res.txt +++ b/tests/parsing/errors/expressions/expected/ambiguousArrow.res.txt @@ -24,6 +24,6 @@ 1) (pattern): int => "test" 2) (pattern: int) => "test" -let a b = ("hi" : int) -let x = ((let a = 1 in let b = 2 in fun pattern -> ("test" : int)) +let a b = ({js|hi|js} : int) +let x = ((let a = 1 in let b = 2 in fun pattern -> ({js|test|js} : int)) [@ns.braces ]) \ No newline at end of file diff --git a/tests/parsing/errors/expressions/expected/emptyeof.res.txt b/tests/parsing/errors/expressions/expected/emptyeof.res.txt index 349c3643..4d299bef 100644 --- a/tests/parsing/errors/expressions/expected/emptyeof.res.txt +++ b/tests/parsing/errors/expressions/expected/emptyeof.res.txt @@ -7,4 +7,5 @@ This string is missing a double quote at the end -let x = "\n" \ No newline at end of file +let x = {js| +|js} \ No newline at end of file diff --git a/tests/parsing/errors/expressions/expected/ifLet.res.txt b/tests/parsing/errors/expressions/expected/ifLet.res.txt index 196aee23..a4a227f4 100644 --- a/tests/parsing/errors/expressions/expected/ifLet.res.txt +++ b/tests/parsing/errors/expressions/expected/ifLet.res.txt @@ -35,10 +35,12 @@ switch result { | _ => () } -;;((match result with | Some x -> Js.log "The sky is blue" | _ -> ()) +;;((match result with | Some x -> Js.log {js|The sky is blue|js} | _ -> ()) [@ns.iflet ][@warning "-4"]) ;;((match result with - | Error x -> Js.log "The sky is red" + | Error x -> Js.log {js|The sky is red|js} | _ -> - (((match result with | Ok y -> Js.log "The sky is blue" | _ -> ())) + (((match result with + | Ok y -> Js.log {js|The sky is blue|js} + | _ -> ())) [@ns.iflet ][@warning "-4"]))[@ns.iflet ][@warning "-4"]) \ No newline at end of file diff --git a/tests/parsing/errors/expressions/expected/taggedTemplateLiterals.res.txt b/tests/parsing/errors/expressions/expected/taggedTemplateLiterals.res.txt index 5b2dad26..3711a2c3 100644 --- a/tests/parsing/errors/expressions/expected/taggedTemplateLiterals.res.txt +++ b/tests/parsing/errors/expressions/expected/taggedTemplateLiterals.res.txt @@ -7,4 +7,4 @@ Tagged template literals are currently restricted to names like: json`null`. -;;{js|null|js} \ No newline at end of file +;;(({js|null|js})[@res.template ]) \ No newline at end of file diff --git a/tests/parsing/errors/expressions/expected/unexpectedConstraint.res.txt b/tests/parsing/errors/expressions/expected/unexpectedConstraint.res.txt index 35e6dcc3..cfa9f898 100644 --- a/tests/parsing/errors/expressions/expected/unexpectedConstraint.res.txt +++ b/tests/parsing/errors/expressions/expected/unexpectedConstraint.res.txt @@ -24,4 +24,4 @@ ("hi": string) let x = ((let a = 1 in let b = 2 in (a + b : int))[@ns.braces ]) -let x = ("hi" : string) \ No newline at end of file +let x = ({js|hi|js} : string) \ No newline at end of file diff --git a/tests/parsing/errors/other/expected/breadcrumbs170.res.txt b/tests/parsing/errors/other/expected/breadcrumbs170.res.txt index 8f950a16..25b22910 100644 --- a/tests/parsing/errors/other/expected/breadcrumbs170.res.txt +++ b/tests/parsing/errors/other/expected/breadcrumbs170.res.txt @@ -18,7 +18,7 @@ module M = struct ;;match l with | None -> [] | Some l -> l#prop end ;;all ;;syntax ;;is -;;"valid" +;;{js|valid|js} ;;it ;;compiles ;;will diff --git a/tests/parsing/errors/pattern/expected/missing.res.txt b/tests/parsing/errors/pattern/expected/missing.res.txt index 4ff671a0..a6a10a2c 100644 --- a/tests/parsing/errors/pattern/expected/missing.res.txt +++ b/tests/parsing/errors/pattern/expected/missing.res.txt @@ -44,5 +44,5 @@ I was expecting a pattern to match on before the `=>` let 2 = [%rescript.exprhole ] -let 4 = for [%rescript.patternhole ] = 0 to 10 do Js.log "for" done +let 4 = for [%rescript.patternhole ] = 0 to 10 do Js.log {js|for|js} done ;;match x with | () -> [%rescript.exprhole ] \ No newline at end of file diff --git a/tests/parsing/errors/pattern/expected/templateLiteral.res.txt b/tests/parsing/errors/pattern/expected/templateLiteral.res.txt index 8c92a720..1412c742 100644 --- a/tests/parsing/errors/pattern/expected/templateLiteral.res.txt +++ b/tests/parsing/errors/pattern/expected/templateLiteral.res.txt @@ -34,5 +34,8 @@ String interpolation is not supported in pattern matching. -let zeroCoord = "0.0" -;;match l with | "" -> () | "" -> () | _ -> () \ No newline at end of file +let zeroCoord = {js|0.0|js} +;;match l with + | (("")[@res.template ]) -> () + | (("")[@res.template ]) -> () + | _ -> () \ No newline at end of file diff --git a/tests/parsing/errors/scanner/expected/escapeSequence.res.txt b/tests/parsing/errors/scanner/expected/escapeSequence.res.txt index 1a0b637b..6757d586 100644 --- a/tests/parsing/errors/scanner/expected/escapeSequence.res.txt +++ b/tests/parsing/errors/scanner/expected/escapeSequence.res.txt @@ -19,5 +19,5 @@ unknown escape sequence -let x = "\\0" -let x = "\\oAAA" \ No newline at end of file +let x = {js|\0|js} +let x = {js|\oAAA|js} \ No newline at end of file diff --git a/tests/parsing/errors/scanner/expected/exoticIdent.res.txt b/tests/parsing/errors/scanner/expected/exoticIdent.res.txt index d32455c1..6e8f2747 100644 --- a/tests/parsing/errors/scanner/expected/exoticIdent.res.txt +++ b/tests/parsing/errors/scanner/expected/exoticIdent.res.txt @@ -43,4 +43,5 @@ let a = b ;;c -;;" = 1\n" \ No newline at end of file +;;{js| = 1 +|js} \ No newline at end of file diff --git a/tests/parsing/errors/scanner/expected/unclosedString.res.txt b/tests/parsing/errors/scanner/expected/unclosedString.res.txt index a3e03f68..059735ce 100644 --- a/tests/parsing/errors/scanner/expected/unclosedString.res.txt +++ b/tests/parsing/errors/scanner/expected/unclosedString.res.txt @@ -7,4 +7,5 @@ This string is missing a double quote at the end -let z = "eof\n" \ No newline at end of file +let z = {js|eof +|js} \ No newline at end of file diff --git a/tests/parsing/errors/structure/expected/gh16A.res.txt b/tests/parsing/errors/structure/expected/gh16A.res.txt index 1306427f..4e8d983a 100644 --- a/tests/parsing/errors/structure/expected/gh16A.res.txt +++ b/tests/parsing/errors/structure/expected/gh16A.res.txt @@ -11,4 +11,4 @@ I'm not sure what to parse here when looking at ")". module C = struct module T = (Fun)(struct ;;foo (a + c) (b + d) end) end -;;Js.log "test" \ No newline at end of file +;;Js.log {js|test|js} \ No newline at end of file diff --git a/tests/parsing/errors/structure/expected/gh16B.res.txt b/tests/parsing/errors/structure/expected/gh16B.res.txt index 898dde5a..23cfa8a5 100644 --- a/tests/parsing/errors/structure/expected/gh16B.res.txt +++ b/tests/parsing/errors/structure/expected/gh16B.res.txt @@ -14,13 +14,17 @@ open Ws let wss = Server.make { port = 82 } let address = wss |. Server.address -let log msg = Js.log ({js|> Server: |js} ^ msg) +let log msg = + Js.log + (((((({js|> Server: |js})[@res.template ]) ^ msg)[@res.template ]) ^ + (({js||js})[@res.template ]))[@res.template ]) ;;log - (((((({js|Running on: |js} ^ address.address) ^ {js|:|js}) ^ - (address.port |. string_of_int)) - ^ {js| (|js}) - ^ address.family) - ^ {js|)|js}) + (((((((((((({js|Running on: |js})[@res.template ]) ^ address.address) + [@res.template ]) ^ (({js|:|js})[@res.template ])) + [@res.template ]) ^ (address.port |. string_of_int)) + ^ (({js| (|js})[@res.template ])) + [@res.template ]) ^ address.family) + ^ (({js|)|js})[@res.template ]))[@res.template ]) module ClientSet = struct module T = @@ -33,4 +37,4 @@ module ClientSet = end) let empty = Belt.Set.make ~id:(((module T))[@ns.namedArgLoc ]) end -;;Js.log "test" \ No newline at end of file +;;Js.log {js|test|js} \ No newline at end of file diff --git a/tests/parsing/errors/typexpr/expected/garbage.res.txt b/tests/parsing/errors/typexpr/expected/garbage.res.txt index 5aef4d25..3c171a7c 100644 --- a/tests/parsing/errors/typexpr/expected/garbage.res.txt +++ b/tests/parsing/errors/typexpr/expected/garbage.res.txt @@ -9,4 +9,4 @@ I'm not sure what to parse here when looking at "?". external printName : name:((unit)[@ns.namedArgLoc ]) -> unit = "printName" -[@@bs.module "moduleName"] \ No newline at end of file +[@@bs.module {js|moduleName|js}] \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/constants.res b/tests/parsing/grammar/expressions/constants.res index 867e4bc7..0d913de0 100644 --- a/tests/parsing/grammar/expressions/constants.res +++ b/tests/parsing/grammar/expressions/constants.res @@ -75,3 +75,19 @@ let x = "\tbar" let x = "\bbar" let x = "\rbar" let x = "\ bar" +let x = "\u00A9" +let x = "\u00a9" +let x = "\u2665" +let a = "\u{000000000061}" +let x = "\u{00A9}" +let x = "\u{00a9}" +let smile = "\u{1F600}" +let smile = "\u{1f600}" +let smile = "\240\159\152\128" + +// represent the same thing +let u = "日本語" +let u = "\u65e5\u672c\u8a9e" +let u = "\u{000065e5}\u{0000672c}\u{00008a9e}" +let u = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" +let u = "\230\151\165\230\156\172\232\170\158" diff --git a/tests/parsing/grammar/expressions/expected/argument.res.txt b/tests/parsing/grammar/expressions/expected/argument.res.txt index 74c8779f..7bc23ec6 100644 --- a/tests/parsing/grammar/expressions/expected/argument.res.txt +++ b/tests/parsing/grammar/expressions/expected/argument.res.txt @@ -6,8 +6,8 @@ let comparisonResult = ((compare currentNode.value ~targetValue:((targetValue)[@ns.namedArgLoc ])) [@bs ]) ;;((callback firstNode ~y:((y)[@ns.namedArgLoc ]))[@bs ]) -;;((document.createElementWithOptions "div" - (elementProps ~onClick:((fun _ -> Js.log "hello world") +;;((document.createElementWithOptions {js|div|js} + (elementProps ~onClick:((fun _ -> Js.log {js|hello world|js}) [@ns.namedArgLoc ])))[@bs ]) ;;((resolve ())[@bs ]) ;;((resolve (let __res_unit = () in __res_unit))[@bs ]) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/arrow.res.txt b/tests/parsing/grammar/expressions/expected/arrow.res.txt index a2194e12..5ab739fe 100644 --- a/tests/parsing/grammar/expressions/expected/arrow.res.txt +++ b/tests/parsing/grammar/expressions/expected/arrow.res.txt @@ -1,12 +1,12 @@ let f x = x + 1 -let f _ = Js.log "test" -let f () = Js.log "unit" +let f _ = Js.log {js|test|js} +let f () = Js.log {js|unit|js} let f (Reducer (inst, comp)) = inst.render comp let f (Instance) = () let f a b = a + b let f 1 2 = () -let f "stringPattern" = () -let f "stringPattern" "stringPattern" = () +let f {js|stringPattern|js} = () +let f {js|stringPattern|js} {js|stringPattern|js} = () let f () = () let f (a : int) (b : int) = a + b let f _ _ = () diff --git a/tests/parsing/grammar/expressions/expected/block.res.txt b/tests/parsing/grammar/expressions/expected/block.res.txt index 4609a59c..09b38117 100644 --- a/tests/parsing/grammar/expressions/expected/block.res.txt +++ b/tests/parsing/grammar/expressions/expected/block.res.txt @@ -23,17 +23,17 @@ let b = [@ns.braces ]) let b = ((f (); g (); h (); (let arr = [|1;2;3|] in ()))[@ns.braces ]) let res = - ((let a = "a starts out as" in + ((let a = {js|a starts out as|js} in (((print_string a; (let a = 20 in print_int a))) [@ns.braces ]); print_string a) [@ns.braces ]) let res = - ((let a = "first its a string" in + ((let a = {js|first its a string|js} in let a = 20 in print_int a; print_int a; print_int a) [@ns.braces ]) let res = - ((let a = "a is always a string" in + ((let a = {js|a is always a string|js} in print_string a; (let b = 30 in print_int b)) [@ns.braces ]) let nestedLet = ((let _ = 1 in ())[@ns.braces ]) @@ -49,10 +49,11 @@ let reifyStyle (type a) (x : 'a) = external canvasGradient : constructor = "CanvasGradient"[@@bs.val ] external canvasPattern : constructor = "CanvasPattern"[@@bs.val ] let instanceOf = - ([%bs.raw {js|function(x,y) {return +(x instanceof y)}|js}] : - 'a -> constructor -> bool) + ([%bs.raw + (({js|function(x,y) {return +(x instanceof y)}|js}) + [@res.template ])] : 'a -> constructor -> bool) end in - ((if (Js.typeof x) = "string" + ((if (Js.typeof x) = {js|string|js} then Obj.magic String else if Internal.instanceOf x Internal.canvasGradient @@ -63,7 +64,7 @@ let reifyStyle (type a) (x : 'a) = else raise (Invalid_argument - "Unknown canvas style kind. Known values are: String, CanvasGradient, CanvasPattern")), + {js|Unknown canvas style kind. Known values are: String, CanvasGradient, CanvasPattern|js})), (Obj.magic x))) [@ns.braces ]) : (a style * a)) let calc_fps t0 t1 = ((let delta = (t1 -. t0) /. 1000. in 1. /. delta) diff --git a/tests/parsing/grammar/expressions/expected/bsObject.res.txt b/tests/parsing/grammar/expressions/expected/bsObject.res.txt index 43d5d47f..c007f765 100644 --- a/tests/parsing/grammar/expressions/expected/bsObject.res.txt +++ b/tests/parsing/grammar/expressions/expected/bsObject.res.txt @@ -1,7 +1,7 @@ let x = [%obj { age = 30 }] let y = [%obj { age = 30 }] -let y = [%obj { age = 30; name = "steve" }] -let y = [%obj { age = 30; name = "steve" }] +let y = [%obj { age = 30; name = {js|steve|js} }] +let y = [%obj { age = 30; name = {js|steve|js} }] let x = (("age")[@ns.braces ]) let x = (("age".(0))[@ns.braces ]) let x = (("age" |. Js.log)[@ns.braces ]) diff --git a/tests/parsing/grammar/expressions/expected/constants.res.txt b/tests/parsing/grammar/expressions/expected/constants.res.txt index ef85a46e..896d1d31 100644 --- a/tests/parsing/grammar/expressions/expected/constants.res.txt +++ b/tests/parsing/grammar/expressions/expected/constants.res.txt @@ -1,13 +1,14 @@ let x = true let y = false -let txt = "a string" -let txtWithEscapedChar = "foo\nbar" +let txt = {js|a string|js} +let txtWithEscapedChar = {js|foo\nbar|js} let number = 1 -let template = {js|amazing +let template = (({js|amazing multine template string -|js} +|js}) + [@res.template ]) let complexNumber = 1.6 let x = 0b0000_0001 let int32 = 42l @@ -49,13 +50,27 @@ let x = '\017' let x = '\170' let x = '\179' let () = ((getResult (); (-10))[@ns.braces ]) -let x = "foo\nbar" -let x = "foo\nbar" -let x = "foo\nbar" -let x = "\\abc" -let x = "'bar" -let x = "\nbar" -let x = "\tbar" -let x = "\bbar" -let x = "\rbar" -let x = " bar" \ No newline at end of file +let x = {js|foo\010bar|js} +let x = {js|foo\x0Abar|js} +let x = {js|foo\o012bar|js} +let x = {js|\\abc|js} +let x = {js|\'bar|js} +let x = {js|\nbar|js} +let x = {js|\tbar|js} +let x = {js|\bbar|js} +let x = {js|\rbar|js} +let x = {js|\ bar|js} +let x = {js|\u00A9|js} +let x = {js|\u00a9|js} +let x = {js|\u2665|js} +let a = {js|\u{000000000061}|js} +let x = {js|\u{00A9}|js} +let x = {js|\u{00a9}|js} +let smile = {js|\u{1F600}|js} +let smile = {js|\u{1f600}|js} +let smile = {js|\240\159\152\128|js} +let u = {js|日本語|js} +let u = {js|\u65e5\u672c\u8a9e|js} +let u = {js|\u{000065e5}\u{0000672c}\u{00008a9e}|js} +let u = {js|\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e|js} +let u = {js|\230\151\165\230\156\172\232\170\158|js} \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/es6template.res.txt b/tests/parsing/grammar/expressions/expected/es6template.res.txt index 3776db36..a179529e 100644 --- a/tests/parsing/grammar/expressions/expected/es6template.res.txt +++ b/tests/parsing/grammar/expressions/expected/es6template.res.txt @@ -1,26 +1,81 @@ -let s = {js|foo|js} -let s = {js|multi +let s = (({js|foo|js})[@res.template ]) +let s = (({js|multi line string -|js} -let s = foo -let s = {js|before|js} ^ foo -let s = {js|before |js} ^ foo -let s = {js|before |js} ^ foo -let s = foo ^ {js|after|js} -let s = foo ^ {js| after|js} -let s = foo ^ {js| after|js} -let s = foo ^ bar -let s = (foo ^ bar) ^ baz -let s = (foo ^ {js| |js}) ^ bar -let s = (((foo ^ {js| |js}) ^ bar) ^ {js| |js}) ^ baz -let s = ((({js| before |js} ^ foo) ^ {js| |js}) ^ bar) ^ {js| after |js} -let s = - ((((({js|before |js} ^ foo) ^ {js| middle |js}) ^ bar) ^ {js| |js}) ^ baz) - ^ {js| wow |js} -let s = - {js| +|js})[@res.template ]) +let s = + (((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ (({js||js}) + [@res.template ])) + [@res.template ]) +let s = + (((((({js|before|js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js||js})[@res.template ])) + [@res.template ]) +let s = + (((((({js|before |js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js||js})[@res.template ])) + [@res.template ]) +let s = + (((((({js|before |js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js||js})[@res.template ])) + [@res.template ]) +let s = + (((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ (({js|after|js}) + [@res.template ])) + [@res.template ]) +let s = + (((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js| after|js})[@res.template ])) + [@res.template ]) +let s = + (((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js| after|js})[@res.template ])) + [@res.template ]) +let s = + ((((((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ (({js||js}) + [@res.template ])) + [@res.template ]) ^ bar) + ^ (({js||js})[@res.template ])) + [@res.template ]) +let s = + (((((((((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js||js})[@res.template ])) + [@res.template ]) ^ bar) + ^ (({js||js})[@res.template ])) + [@res.template ]) ^ baz) + ^ (({js||js})[@res.template ])) + [@res.template ]) +let s = + ((((((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ (({js| |js}) + [@res.template ])) + [@res.template ]) ^ bar) + ^ (({js||js})[@res.template ])) + [@res.template ]) +let s = + (((((((((((({js||js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js| |js})[@res.template ])) + [@res.template ]) ^ bar) + ^ (({js| |js})[@res.template ])) + [@res.template ]) ^ baz) + ^ (({js||js})[@res.template ])) + [@res.template ]) +let s = + ((((((((({js| before |js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js| |js})[@res.template ])) + [@res.template ]) ^ bar) + ^ (({js| after |js})[@res.template ])) + [@res.template ]) +let s = + (((((((((((({js|before |js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js| middle |js})[@res.template ])) + [@res.template ]) ^ bar) + ^ (({js| |js})[@res.template ])) + [@res.template ]) ^ baz) + ^ (({js| wow |js})[@res.template ])) + [@res.template ]) +let s = + (({js| multiline es6 @@ -32,13 +87,21 @@ let s = so convenient :) -|js} -let s = {js|$dollar without $braces $interpolation|js} -let s = {json|null|json} -let x = {js|foo`bar$\foo|js} -let x = ((({js|foo`bar$\foo|js} ^ a) ^ {js| ` |js}) ^ b) ^ {js| ` xx|js} -let thisIsFine = {js|$something|js} -let thisIsAlsoFine = {js|fine$|js} -let isThisFine = {js|shouldBeFine$|js} -;;{js|$|js} ^ dollarAmountInt -;;{js|$|js} ^ dollarAmountInt \ No newline at end of file +|js}) + [@res.template ]) +let s = (({js|$dollar without $braces $interpolation|js})[@res.template ]) +let s = (({json|null|json})[@res.template ]) +let x = (({js|foo`bar$\foo|js})[@res.template ]) +let x = + ((((((((({js|foo`bar$\foo|js})[@res.template ]) ^ a)[@res.template ]) ^ + (({js| ` |js})[@res.template ])) + [@res.template ]) ^ b) + ^ (({js| ` xx|js})[@res.template ])) + [@res.template ]) +let thisIsFine = (({js|$something|js})[@res.template ]) +let thisIsAlsoFine = (({js|fine$|js})[@res.template ]) +let isThisFine = (({js|shouldBeFine$|js})[@res.template ]) +;;(((((({js|$|js})[@res.template ]) ^ dollarAmountInt)[@res.template ]) ^ + (({js||js})[@res.template ]))[@res.template ]) +;;(((((({js|$|js})[@res.template ]) ^ dollarAmountInt)[@res.template ]) ^ + (({js||js})[@res.template ]))[@res.template ]) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/extension.res.txt b/tests/parsing/grammar/expressions/expected/extension.res.txt index f1ab923c..b97d310d 100644 --- a/tests/parsing/grammar/expressions/expected/extension.res.txt +++ b/tests/parsing/grammar/expressions/expected/extension.res.txt @@ -1,5 +1,5 @@ ;;[%expr ] ;;[%expr.extension ] -;;[%expr.extension.with.args "argument"] +;;[%expr.extension.with.args {js|argument|js}] ;;[%expr.extension.with.args fun x -> f x] -let x = ([%bs.raw "1"]) + ([%bs.raw "2"]) \ No newline at end of file +let x = ([%bs.raw {js|1|js}]) + ([%bs.raw {js|2|js}]) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/firstClassModule.res.txt b/tests/parsing/grammar/expressions/expected/firstClassModule.res.txt index 9c6d5d2f..6a80380c 100644 --- a/tests/parsing/grammar/expressions/expected/firstClassModule.res.txt +++ b/tests/parsing/grammar/expressions/expected/firstClassModule.res.txt @@ -45,22 +45,22 @@ let build_dispatch_table handlers = ;;((module Teenager) |. age) |. Js.log ;;((module Teenager).(0)) |. Js.log ;;((if ((module Teenager) |. age) |. isAdult - then Js.log "has responsibilities" - else Js.log "can play in the playground")[@ns.ternary ]) + then Js.log {js|has responsibilities|js} + else Js.log {js|can play in the playground|js})[@ns.ternary ]) ;;((if ((module Streets).(0)) |. isExpensive - then Js.log "big money" - else Js.log "affordable")[@ns.ternary ]) + then Js.log {js|big money|js} + else Js.log {js|affordable|js})[@ns.ternary ]) let () = ((((module Teenager) |. age) |. Js.log)[@ns.braces ]) let () = (((module Teenager).(0))[@ns.braces ]) let () = ((if ((module Teenager) |. age) |. isAdult - then Js.log "has responsibilities" - else Js.log "can play in the playground") + then Js.log {js|has responsibilities|js} + else Js.log {js|can play in the playground|js}) [@ns.braces ][@ns.ternary ]) let () = ((if ((module Streets).(0)) |. isExpensive - then Js.log "big money" - else Js.log "affordable") + then Js.log {js|big money|js} + else Js.log {js|affordable|js}) [@ns.braces ][@ns.ternary ]) let () = ((let a = 1 in @@ -71,7 +71,7 @@ let () = let b = 2 in ((module Teenager) |. age) |. Js.log; ((if (((module Teenager).(0)) |. age) |. isAdult - then Js.log "has responsibilities" - else Js.log "can play in the playground") + then Js.log {js|has responsibilities|js} + else Js.log {js|can play in the playground|js}) [@ns.ternary ])) [@ns.braces ]) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/infix.res.txt b/tests/parsing/grammar/expressions/expected/infix.res.txt index 7126c043..0d8bbd28 100644 --- a/tests/parsing/grammar/expressions/expected/infix.res.txt +++ b/tests/parsing/grammar/expressions/expected/infix.res.txt @@ -1,5 +1,5 @@ ;;a |. (f b) -;;"string1" ^ "string2" +;;{js|string1|js} ^ {js|string2|js} ;;a <> b ;;a != b ;;a = b diff --git a/tests/parsing/grammar/expressions/expected/jsx.res.txt b/tests/parsing/grammar/expressions/expected/jsx.res.txt index 0a3c9c66..035598f7 100644 --- a/tests/parsing/grammar/expressions/expected/jsx.res.txt +++ b/tests/parsing/grammar/expressions/expected/jsx.res.txt @@ -1,29 +1,29 @@ let _ = ((div ~children:[] ())[@JSX ]) let _ = ((div ~children:[] ())[@JSX ]) -let _ = ((div ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] ()) +let _ = ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) ~children:[] ()) [@JSX ]) -let _ = ((div ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] ()) +let _ = ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) ~children:[] ()) [@JSX ]) -let _ = ((div ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] ()) +let _ = ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) ~children:[] ()) [@JSX ]) -let _ = ((div ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] ()) +let _ = ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) ~children:[] ()) [@JSX ]) let _ = - ((div ~className:(("menu")[@ns.namedArgLoc ]) - ~onClick:((fun _ -> Js.log "click")[@ns.namedArgLoc ][@ns.braces ]) - ~children:[] ()) + ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~onClick:((fun _ -> Js.log {js|click|js}) + [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]) let _ = - ((div ~className:(("menu")[@ns.namedArgLoc ]) - ~onClick:((fun _ -> Js.log "click")[@ns.namedArgLoc ][@ns.braces ]) - ~children:[] ()) + ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~onClick:((fun _ -> Js.log {js|click|js}) + [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]) let _ = ((Navbar.createElement ~children:[] ())[@JSX ]) let _ = ((Navbar.createElement ~children:[] ())[@JSX ]) let _ = ((Navbar.createElement ~children:[] ())[@JSX ]) let _ = - ((Navbar.createElement ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] - ()) + ((Navbar.createElement ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~children:[] ()) [@JSX ]) let _ = ((Dot.Up.createElement ~children:[] ())[@JSX ]) let _ = ((Dot.Up.createElement ~children:[] ())[@JSX ]) @@ -37,8 +37,8 @@ let _ = ~children:[((Dot.Up.createElement ~children:[] ())[@JSX ])] ()) [@JSX ]) let _ = - ((Dot.Up.createElement ~className:(("menu")[@ns.namedArgLoc ]) ~children:[] - ()) + ((Dot.Up.createElement ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~children:[] ()) [@JSX ]) let _ = ((Dot.low.createElement ~children:[] ())[@JSX ]) let _ = ((Dot.low.createElement ~children:[] ())[@JSX ]) @@ -52,7 +52,7 @@ let _ = ~children:[((Dot.low.createElement ~children:[] ())[@JSX ])] ()) [@JSX ]) let _ = - ((Dot.low.createElement ~className:(("menu")[@ns.namedArgLoc ]) + ((Dot.low.createElement ~className:(({js|menu|js})[@ns.namedArgLoc ]) ~children:[] ()) [@JSX ]) let _ = ((el ~punned:((punned)[@ns.namedArgLoc ]) ~children:[] ())[@JSX ]) @@ -64,20 +64,20 @@ let _ = ((el ?a:((b)[@ns.namedArgLoc ]) ~children:[] ())[@JSX ]) let _ = (([])[@JSX ]) let _ = (([])[@JSX ]) let _ = - ((div ~className:(("menu")[@ns.namedArgLoc ]) - ~children:[((div ~className:(("submenu")[@ns.namedArgLoc ]) + ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~children:[((div ~className:(({js|submenu|js})[@ns.namedArgLoc ]) ~children:[sub1] ()) [@JSX ]); - ((div ~className:(("submenu")[@ns.namedArgLoc ]) + ((div ~className:(({js|submenu|js})[@ns.namedArgLoc ]) ~children:[sub2] ()) [@JSX ])] ()) [@JSX ]) let _ = - ((div ~className:(("menu")[@ns.namedArgLoc ]) - ~children:[((div ~className:(("submenu")[@ns.namedArgLoc ]) + ((div ~className:(({js|menu|js})[@ns.namedArgLoc ]) + ~children:[((div ~className:(({js|submenu|js})[@ns.namedArgLoc ]) ~children:[sub1] ()) [@JSX ]); - ((div ~className:(("submenu")[@ns.namedArgLoc ]) + ((div ~className:(({js|submenu|js})[@ns.namedArgLoc ]) ~children:[sub2] ()) [@JSX ])] ()) [@JSX ]) @@ -99,7 +99,7 @@ let _ = [@JSX ]) let _ = ((div ~onClick:((onClickHandler)[@ns.namedArgLoc ]) - ~children:[((["foobar"])[@JSX ])] ()) + ~children:[(([{js|foobar|js}])[@JSX ])] ()) [@JSX ]) let _ = ((Window.createElement @@ -212,10 +212,10 @@ let tuples = let icon = ((Icon.createElement ~name:((match state.volume with - | v when v < 0.1 -> "sound-off" - | v when v < 0.11 -> "sound-min" - | v when v < 0.51 -> "sound-med" - | _ -> "sound-max")[@ns.namedArgLoc ][@ns.braces ]) + | v when v < 0.1 -> {js|sound-off|js} + | v when v < 0.11 -> {js|sound-min|js} + | v when v < 0.51 -> {js|sound-med|js} + | _ -> {js|sound-max|js})[@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]) let _ = @@ -253,19 +253,19 @@ let y = [@JSX ])|] let _ = ((Description.createElement - ~term:((Text.createElement ~text:(("Age")[@ns.namedArgLoc ]) + ~term:((Text.createElement ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:[] ())[@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) let _ = ((Description.createElement - ~term:((Text.createElement ~text:(("Age")[@ns.namedArgLoc ]) + ~term:((Text.createElement ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:(([||])[@ns.namedArgLoc ]) ()) [@ns.namedArgLoc ][@ns.braces ]) ~children:[child] ()) [@JSX ]) let _ = ((Description.createElement - ~term:((Text.createElement ~text:(("Age")[@ns.namedArgLoc ]) ()) + ~term:((Text.createElement ~text:(({js|Age|js})[@ns.namedArgLoc ]) ()) [@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) let _ = @@ -273,7 +273,7 @@ let _ = ~term:((Text.createElement ~superLongPunnedProp:((superLongPunnedProp) [@ns.namedArgLoc ]) ~anotherSuperLongOneCrazyLongThingHere:((anotherSuperLongOneCrazyLongThingHere) - [@ns.namedArgLoc ]) ~text:(("Age")[@ns.namedArgLoc ]) + [@ns.namedArgLoc ]) ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:[] ())[@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) @@ -285,27 +285,28 @@ let _ = [@ns.namedArgLoc ]) ~children:[] ()) [@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[] ()) [@JSX ]) -let _ = ((div ~children:[((span ~children:[str "hello"] ())[@JSX ])] ()) +let _ = + ((div ~children:[((span ~children:[str {js|hello|js}] ())[@JSX ])] ()) [@JSX ]) let _ = ((description - ~term:((text ~text:(("Age")[@ns.namedArgLoc ]) ~children:[] ()) + ~term:((text ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:[] ()) [@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) let _ = ((description - ~term:((text ~text:(("Age")[@ns.namedArgLoc ]) ~children:(([||]) - [@ns.namedArgLoc ]) ())[@ns.namedArgLoc ][@ns.braces ]) + ~term:((text ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:(( + [||])[@ns.namedArgLoc ]) ())[@ns.namedArgLoc ][@ns.braces ]) ~children:[child] ()) [@JSX ]) let _ = ((description - ~term:((text ~text:(("Age")[@ns.namedArgLoc ]) ~children:(([||]) - [@ns.namedArgLoc ]))[@ns.namedArgLoc ][@ns.braces ][@JSX ]) - ~children:[child] ()) + ~term:((text ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:(( + [||])[@ns.namedArgLoc ])) + [@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) let _ = - ((description ~term:((text ~text:(("Age")[@ns.namedArgLoc ]) ()) + ((description ~term:((text ~text:(({js|Age|js})[@ns.namedArgLoc ]) ()) [@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) let _ = @@ -313,7 +314,7 @@ let _ = ~term:((div ~superLongPunnedProp:((superLongPunnedProp) [@ns.namedArgLoc ]) ~anotherSuperLongOneCrazyLongThingHere:((anotherSuperLongOneCrazyLongThingHere) - [@ns.namedArgLoc ]) ~text:(("Age")[@ns.namedArgLoc ]) + [@ns.namedArgLoc ]) ~text:(({js|Age|js})[@ns.namedArgLoc ]) ~children:[] ())[@ns.namedArgLoc ][@ns.braces ][@JSX ]) ~children:[child] ()) [@JSX ]) @@ -396,37 +397,39 @@ let _ = let _ = ((div ~children:[(((match color with - | Black -> ReasonReact.string "black" - | Red -> ReasonReact.string "red")) + | Black -> ReasonReact.string {js|black|js} + | Red -> ReasonReact.string {js|red|js})) [@ns.braces ])] ()) [@JSX ]) let _ = ((div - ~style:((ReactDOMRe.Style.make ~width:(("20px")[@ns.namedArgLoc ]) - ~height:(("20px")[@ns.namedArgLoc ]) ~borderRadius:(("100%") - [@ns.namedArgLoc ]) ~backgroundColor:(("red") + ~style:((ReactDOMRe.Style.make ~width:(({js|20px|js}) + [@ns.namedArgLoc ]) ~height:(({js|20px|js}) + [@ns.namedArgLoc ]) ~borderRadius:(({js|100%|js}) + [@ns.namedArgLoc ]) ~backgroundColor:(({js|red|js}) [@ns.namedArgLoc ]))[@ns.namedArgLoc ][@ns.braces ][@foo ]) ~children:[] ()) [@JSX ]) let _ = ((Animated.createElement ~initialValue:((0.0)[@ns.namedArgLoc ]) ~value:((value)[@ns.namedArgLoc ]) - ~children:((ReactDOMRe.Style.make ~width:(("20px")[@ns.namedArgLoc ]) - ~height:(("20px")[@ns.namedArgLoc ]) - ~borderRadius:(("100%")[@ns.namedArgLoc ]) - ~backgroundColor:(("red")[@ns.namedArgLoc ])) - [@ns.braces ]) ()) + ~children:((ReactDOMRe.Style.make ~width:(({js|20px|js}) + [@ns.namedArgLoc ]) ~height:(({js|20px|js}) + [@ns.namedArgLoc ]) ~borderRadius:(({js|100%|js}) + [@ns.namedArgLoc ]) ~backgroundColor:(({js|red|js}) + [@ns.namedArgLoc ]))[@ns.braces ]) ()) [@JSX ]) let _ = ((Animated.createElement ~initialValue:((0.0)[@ns.namedArgLoc ]) ~value:((value)[@ns.namedArgLoc ]) ~children:((fun value -> ((div - ~style:((ReactDOMRe.Style.make ~width:(("20px") - [@ns.namedArgLoc ]) ~height:(("20px") + ~style:((ReactDOMRe.Style.make ~width:(({js|20px|js}) [@ns.namedArgLoc ]) - ~borderRadius:(("100%")[@ns.namedArgLoc ]) - ~backgroundColor:(("red") + ~height:(({js|20px|js})[@ns.namedArgLoc ]) + ~borderRadius:(({js|100%|js}) + [@ns.namedArgLoc ]) + ~backgroundColor:(({js|red|js}) [@ns.namedArgLoc ])) [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]))[@ns.braces ]) ()) @@ -436,12 +439,13 @@ let _ = ~value:((value)[@ns.namedArgLoc ]) ~children:((fun value -> (((div - ~style:((ReactDOMRe.Style.make ~width:(("20px") - [@ns.namedArgLoc ]) ~height:(("20px") + ~style:((ReactDOMRe.Style.make + ~width:(({js|20px|js})[@ns.namedArgLoc ]) + ~height:(({js|20px|js}) [@ns.namedArgLoc ]) - ~borderRadius:(("100%") + ~borderRadius:(({js|100%|js}) [@ns.namedArgLoc ]) - ~backgroundColor:(("red") + ~backgroundColor:(({js|red|js}) [@ns.namedArgLoc ])) [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]) : ReasonReact.element))[@ns.braces ]) ()) @@ -451,11 +455,12 @@ let _ = ~value:((value)[@ns.namedArgLoc ]) ~children:((fun value -> ((div - ~style:((ReactDOMRe.Style.make ~width:(("20px") - [@ns.namedArgLoc ]) ~height:(("20px") + ~style:((ReactDOMRe.Style.make ~width:(({js|20px|js}) + [@ns.namedArgLoc ]) + ~height:(({js|20px|js})[@ns.namedArgLoc ]) + ~borderRadius:(({js|100%|js}) [@ns.namedArgLoc ]) - ~borderRadius:(("100%")[@ns.namedArgLoc ]) - ~backgroundColor:(("red") + ~backgroundColor:(({js|red|js}) [@ns.namedArgLoc ])) [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@ns.braces ][@JSX ]))[@ns.braces ][@foo ]) ()) @@ -464,15 +469,15 @@ let _ = ((Animated.createElement ~initialValue:((0.0)[@ns.namedArgLoc ]) ~value:((value)[@ns.namedArgLoc ]) ~children:((fun value -> - ((let width = "20px" in - let height = "20px" in + ((let width = {js|20px|js} in + let height = {js|20px|js} in ((div ~style:((ReactDOMRe.Style.make ~width:((width) [@ns.namedArgLoc ]) ~height:((height) [@ns.namedArgLoc ]) - ~borderRadius:(("100%") + ~borderRadius:(({js|100%|js}) [@ns.namedArgLoc ]) - ~backgroundColor:(("red") + ~backgroundColor:(({js|red|js}) [@ns.namedArgLoc ])) [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ])) @@ -484,19 +489,19 @@ let _ = [@JSX ]) let _ = ((button ?id:((id)[@ns.namedArgLoc ]) - ~className:((Cn.make [|"button";"is-fullwidth"|]) + ~className:((Cn.make [|{js|button|js};{js|is-fullwidth|js}|]) [@ns.namedArgLoc ][@ns.braces ]) ~onClick:((onClick)[@ns.namedArgLoc ]) ~children:[(("Submit" |> ste)[@ns.braces ])] ()) [@JSX ]) let _ = ((button ?id:((id)[@ns.namedArgLoc ]) - ~className:((Cn.make ["button"; "is-fullwidth"]) + ~className:((Cn.make [{js|button|js}; {js|is-fullwidth|js}]) [@ns.namedArgLoc ][@ns.braces ]) ~onClick:((onClick)[@ns.namedArgLoc ]) ~children:[(("Submit" |> ste)[@ns.braces ])] ()) [@JSX ]) let _ = ((button ?id:((id)[@ns.namedArgLoc ]) - ~className:((Cn.make ("button", "is-fullwidth")) + ~className:((Cn.make ({js|button|js}, {js|is-fullwidth|js})) [@ns.namedArgLoc ][@ns.braces ]) ~onClick:((onClick)[@ns.namedArgLoc ]) ~children:[(("Submit" |> ste)[@ns.braces ])] ()) [@JSX ]) @@ -506,23 +511,25 @@ let _ = ~children:[(("Submit" |> ste)[@ns.braces ])] ()) [@JSX ]) let _ = - ((X.createElement ~y:((z |. (Belt.Option.getWithDefault "")) + ((X.createElement ~y:((z |. (Belt.Option.getWithDefault {js||js})) [@ns.namedArgLoc ][@ns.braces ]) ~children:[] ()) [@JSX ]) let _ = ((div ~style:((getStyle ())[@ns.namedArgLoc ][@ns.braces ]) - ~children:[((ReasonReact.string "BugTest")[@ns.braces ])] ()) + ~children:[((ReasonReact.string {js|BugTest|js})[@ns.braces ])] ()) [@JSX ]) let _ = ((div ~children:[(((let left = limit |. Int.toString in - (left ^ {js| characters left|js}) |. React.string)) + (((((({js||js})[@res.template ]) ^ left)[@res.template ]) + ^ (({js| characters left|js})[@res.template ])) + [@res.template ]) |. React.string)) [@ns.braces ])] ()) [@JSX ]) let _ = ((View.createElement ~style:((styles#backgroundImageWrapper) [@ns.namedArgLoc ]) - ~children:[(((let uri = "/images/header-background.png" in + ~children:[(((let uri = {js|/images/header-background.png|js} in ((Image.createElement ~resizeMode:((Contain) [@ns.namedArgLoc ]) ~style:((styles#backgroundImage) [@ns.namedArgLoc ]) ~uri:((uri)[@ns.namedArgLoc ]) diff --git a/tests/parsing/grammar/expressions/expected/parenthesized.res.txt b/tests/parsing/grammar/expressions/expected/parenthesized.res.txt index 59f02931..b097fb35 100644 --- a/tests/parsing/grammar/expressions/expected/parenthesized.res.txt +++ b/tests/parsing/grammar/expressions/expected/parenthesized.res.txt @@ -4,20 +4,24 @@ let truth = true let truth = false let constructor = None let longidentConstructor = Option.None -let txt = "a string" -let otherTxt = {js|foo bar |js} ^ txt +let txt = {js|a string|js} +let otherTxt = + (((((({js|foo bar |js})[@res.template ]) ^ txt)[@res.template ]) ^ + (({js||js})[@res.template ])) + [@res.template ]) let ident = myIdent let aList = [1; 2] let anArray = [|1;2|] let aTuple = (1, 2) -let aRecord = { name = "steve"; age = 30 } +let aRecord = { name = {js|steve|js}; age = 30 } let blockExpression = ((let a = 1 in let b = 2 in a + b)[@ns.braces ]) let assertSmthing = assert true let lazyThing = lazy true -let jsx = ((div ~className:(("cx")[@ns.namedArgLoc ]) ~children:[foo] ()) +let jsx = + ((div ~className:(({js|cx|js})[@ns.namedArgLoc ]) ~children:[foo] ()) [@JSX ]) let ifExpr = if true then Js.log true else Js.log false let forExpr = for p = 0 to 10 do () done let whileExpr = while true do doSomeImperativeThing () done -let switchExpr = match myVar with | Blue -> "blue" | Red -> "red" +let switchExpr = match myVar with | Blue -> {js|blue|js} | Red -> {js|red|js} let constrainedExpr = (x : int) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/polyvariant.res.txt b/tests/parsing/grammar/expressions/expected/polyvariant.res.txt index 93f71610..5de14a9e 100644 --- a/tests/parsing/grammar/expressions/expected/polyvariant.res.txt +++ b/tests/parsing/grammar/expressions/expected/polyvariant.res.txt @@ -5,5 +5,5 @@ let animation = `ease-in let one = `1 let fortyTwo = `42 let long = `42444 -let oneString = `1 "payload" -let twoIntString = `2 (3, "payload") \ No newline at end of file +let oneString = `1 {js|payload|js} +let twoIntString = `2 (3, {js|payload|js}) \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/switch.res.txt b/tests/parsing/grammar/expressions/expected/switch.res.txt index 662922f8..520fe4fb 100644 --- a/tests/parsing/grammar/expressions/expected/switch.res.txt +++ b/tests/parsing/grammar/expressions/expected/switch.res.txt @@ -5,7 +5,7 @@ ;;match person1 with | Teacher _ -> () | Student { reportCard = { gpa } } when gpa < 0.5 -> - Js.log "What's happening" + Js.log {js|What's happening|js} | Student { reportCard = { gpa } } when gpa > 0.9 -> - Js.log "Take more free time, you study too much." - | Student _ -> Js.log "Heyo" \ No newline at end of file + Js.log {js|Take more free time, you study too much.|js} + | Student _ -> Js.log {js|Heyo|js} \ No newline at end of file diff --git a/tests/parsing/grammar/expressions/expected/try.res.txt b/tests/parsing/grammar/expressions/expected/try.res.txt index af7802e9..4d6f59ba 100644 --- a/tests/parsing/grammar/expressions/expected/try.res.txt +++ b/tests/parsing/grammar/expressions/expected/try.res.txt @@ -1,5 +1,6 @@ ;;try ((let x = 1 in let y = 2 in dangerousCall (x + y))[@ns.braces ]) - with | Foo -> Js.log "catched Foo" | Exit -> Js.log "catched exit" -;;try myDangerousFn () with | Foo -> Js.log "catched Foo"[@@attr ] + with | Foo -> Js.log {js|catched Foo|js} + | Exit -> Js.log {js|catched exit|js} +;;try myDangerousFn () with | Foo -> Js.log {js|catched Foo|js}[@@attr ] let x = ((let y = 1 in try ((apply y)[@ns.braces ]) with | _ -> 2) [@ns.braces ]) \ No newline at end of file diff --git a/tests/parsing/grammar/ffi/expected/export.res.txt b/tests/parsing/grammar/ffi/expected/export.res.txt index 1a207c99..0df452bf 100644 --- a/tests/parsing/grammar/ffi/expected/export.res.txt +++ b/tests/parsing/grammar/ffi/expected/export.res.txt @@ -5,11 +5,11 @@ type nonrec t = int[@@genType ] and s = string type nonrec t = int and s = string[@@genType ] -let callback _ = Js.log "Clicked"[@@genType ] -let callback _ = Js.log "Clicked"[@@genType ] -let x = "hello world"[@@genType ] +let callback _ = Js.log {js|Clicked|js}[@@genType ] +let callback _ = Js.log {js|Clicked|js}[@@genType ] +let x = {js|hello world|js}[@@genType ] and y = 2[@@genType ] -let x = "hello world"[@@genType ] +let x = {js|hello world|js}[@@genType ] and y = 2[@@genType ] -let x = "hello world" +let x = {js|hello world|js} and y = 2[@@genType ] \ No newline at end of file diff --git a/tests/parsing/grammar/modtype/expected/extension.res.txt b/tests/parsing/grammar/modtype/expected/extension.res.txt index 5e99081f..78109f19 100644 --- a/tests/parsing/grammar/modtype/expected/extension.res.txt +++ b/tests/parsing/grammar/modtype/expected/extension.res.txt @@ -1,3 +1,3 @@ module type T = [%ext ] -module type T = [%ext.with.args "argument"] +module type T = [%ext.with.args {js|argument|js}] module type T = (([%ext ])[@attr ]) \ No newline at end of file diff --git a/tests/parsing/grammar/pattern/expected/constant.res.txt b/tests/parsing/grammar/pattern/expected/constant.res.txt index 2eaa0a72..ab089140 100644 --- a/tests/parsing/grammar/pattern/expected/constant.res.txt +++ b/tests/parsing/grammar/pattern/expected/constant.res.txt @@ -1,22 +1,22 @@ -let "stringPattern" = () -let "stringPattern" as s = () -let ("stringPattern" : string) = () -let ("stringPattern" : string) as s = () +let {js|stringPattern|js} = () +let {js|stringPattern|js} as s = () +let ({js|stringPattern|js} : string) = () +let ({js|stringPattern|js} : string) as s = () ;;match x with - | "stringPattern" -> () - | "stringPattern" as s -> () - | ("stringPattern" : string) as s -> () -;;for "stringPattern" = 0 to 10 do () done -;;for "stringPattern" as s = 0 to 10 do () done -;;for "stringPattern" = 0 to 10 do () done -;;for "stringPattern" as s = 0 to 10 do () done -;;for "stringPattern" as s = 0 to 10 do () done -let f "stringPattern" = () -let f ("stringPattern" as s) = () -let f ("stringPattern" as s) = () -let f ("stringPattern" : string) = () -let f (("stringPattern" : string) as s) = () -let f ("stringPattern" : string) = () + | {js|stringPattern|js} -> () + | {js|stringPattern|js} as s -> () + | ({js|stringPattern|js} : string) as s -> () +;;for {js|stringPattern|js} = 0 to 10 do () done +;;for {js|stringPattern|js} as s = 0 to 10 do () done +;;for {js|stringPattern|js} = 0 to 10 do () done +;;for {js|stringPattern|js} as s = 0 to 10 do () done +;;for {js|stringPattern|js} as s = 0 to 10 do () done +let f {js|stringPattern|js} = () +let f ({js|stringPattern|js} as s) = () +let f ({js|stringPattern|js} as s) = () +let f ({js|stringPattern|js} : string) = () +let f (({js|stringPattern|js} : string) as s) = () +let f ({js|stringPattern|js} : string) = () let 1 = () let 1 as x = () let (1 : int) = () @@ -46,11 +46,11 @@ let f (1 : int) = () let _0 = 0x9A let print ppf i = match i.stamp with - | 0 -> fprintf ppf "%s!" i.name - | (-1) -> fprintf ppf "%s#" i.name - | 1 -> fprintf ppf "%s#" i.name - | (-1.) -> fprintf ppf "%s#" i.name - | 1. -> fprintf ppf "%s#" i.name + | 0 -> fprintf ppf {js|%s!|js} i.name + | (-1) -> fprintf ppf {js|%s#|js} i.name + | 1 -> fprintf ppf {js|%s#|js} i.name + | (-1.) -> fprintf ppf {js|%s#|js} i.name + | 1. -> fprintf ppf {js|%s#|js} i.name let (-1)..(-1.) = x ;;match science with | (1.12, (-3.13)) -> true @@ -66,18 +66,30 @@ let (-1)..(-1.) = x | exception 19.34 -> true | _ -> false ;;match literal with - | {js|literal|js} -> true - | ({js|literal1|js}, {js|literal2|js}) -> true - | [|{js|literal1|js};{js|literal2|js}|] -> true - | {js|literal1|js}::{js|literal2|js}::[] -> true - | { x = {js|literal1|js}; y = {js|literal2|js} } -> true - | Constructor ({js|literal1|js}, {js|literal2|js}) -> true - | `Constuctor ({js|literal1|js}, {js|literal2|js}) -> true - | {js|literal|js} as x -> true - | {js|literal|js}|{js|literal|js} -> true - | ({js|literal|js} : string) -> true - | (lazy {js|literal|js}) -> true - | exception {js|literal|js} -> true + | (({js|literal|js})[@res.template ]) -> true + | ((({js|literal1|js})[@res.template ]), + (({js|literal2|js})[@res.template ])) -> true + | [|(({js|literal1|js})[@res.template ]);(({js|literal2|js})[@res.template + ])|] + -> true + | (({js|literal1|js})[@res.template ])::(({js|literal2|js})[@res.template ])::[] + -> true + | { x = (({js|literal1|js})[@res.template ]); + y = (({js|literal2|js})[@res.template ]) } -> true + | Constructor + ((({js|literal1|js})[@res.template ]), + (({js|literal2|js})[@res.template ])) + -> true + | `Constuctor + ((({js|literal1|js})[@res.template ]), + (({js|literal2|js})[@res.template ])) + -> true + | (({js|literal|js})[@res.template ]) as x -> true + | (({js|literal|js})[@res.template ])|(({js|literal|js})[@res.template ]) + -> true + | ((({js|literal|js})[@res.template ]) : string) -> true + | (lazy (({js|literal|js})[@res.template ])) -> true + | exception (({js|literal|js})[@res.template ]) -> true | _ -> false -let {js|literal constant|js} = x -;;for {js|literal constant|js} = 0 to 10 do () done \ No newline at end of file +let (({js|literal constant|js})[@res.template ]) = x +;;for (({js|literal constant|js})[@res.template ]) = 0 to 10 do () done \ No newline at end of file diff --git a/tests/parsing/grammar/pattern/expected/constructor.res.txt b/tests/parsing/grammar/pattern/expected/constructor.res.txt index 2c59bbcc..45783c9c 100644 --- a/tests/parsing/grammar/pattern/expected/constructor.res.txt +++ b/tests/parsing/grammar/pattern/expected/constructor.res.txt @@ -69,4 +69,6 @@ let f (Instance (comp : Component.t) : React.t) = () ;;for Point { x; y; z } = x to y do () done ;;for Point { x; y; z } = x to y do () done ;;for Point { x; y; z } as p = x to y do () done -;;match truth with | true -> Js.log "true" | false -> Js.log "false" \ No newline at end of file +;;match truth with + | true -> Js.log {js|true|js} + | false -> Js.log {js|false|js} \ No newline at end of file diff --git a/tests/parsing/grammar/pattern/expected/extension.res.txt b/tests/parsing/grammar/pattern/expected/extension.res.txt index 7a627c57..1f14e535 100644 --- a/tests/parsing/grammar/pattern/expected/extension.res.txt +++ b/tests/parsing/grammar/pattern/expected/extension.res.txt @@ -1,8 +1,8 @@ let [%patternExtension ] = () let [%pattern.extension ] = () -let [%bs.raw "x"] = () -let ([%bs.raw "x"] : unit) = () -let [%bs.raw "x"] as y = () +let [%bs.raw {js|x|js}] = () +let ([%bs.raw {js|x|js}] : unit) = () +let [%bs.raw {js|x|js}] as y = () let [%patExt1 ]|[%patExt2 ] = () ;;match x with | [%patternExtension ] -> () @@ -13,10 +13,10 @@ let [%patExt1 ]|[%patExt2 ] = () | [%patExt1 ]|[%patExt2 ] -> () let f [%patternExtension ] = () let f [%pattern.extension ] = () -let f [%bs.raw "x"] = () -let f [%bs.raw "x"] [%bs.raw "y"] = () -let f ([%bs.raw "x"] as _y) = () -let f ([%bs.raw "x"] : unit) = () +let f [%bs.raw {js|x|js}] = () +let f [%bs.raw {js|x|js}] [%bs.raw {js|y|js}] = () +let f ([%bs.raw {js|x|js}] as _y) = () +let f ([%bs.raw {js|x|js}] : unit) = () let f ([%patExt1 ]|[%patExt2 ]) = () ;;for [%ext ] = x to y do () done ;;for [%ext1 ]|[%ext2 ] = x to y do () done diff --git a/tests/parsing/grammar/signature/expected/include.res.txt b/tests/parsing/grammar/signature/expected/include.res.txt index 2311b4fd..0ffe798a 100644 --- a/tests/parsing/grammar/signature/expected/include.res.txt +++ b/tests/parsing/grammar/signature/expected/include.res.txt @@ -11,7 +11,7 @@ module type Sig = include ((sig val s : string val y : int end)[@onSignature ])[@@onInclude ] include [%extension ] - include [%extension.with.args "foo"] + include [%extension.with.args {js|foo|js}] include (([%extension ])[@onExtension ])[@@onInclude ] include (Foo with type t = string) include (((Foo)[@onModType ]) with type t = string)[@@onInclude ] diff --git a/tests/parsing/grammar/signature/expected/itemExtension.res.txt b/tests/parsing/grammar/signature/expected/itemExtension.res.txt index 474fade5..db4bcef9 100644 --- a/tests/parsing/grammar/signature/expected/itemExtension.res.txt +++ b/tests/parsing/grammar/signature/expected/itemExtension.res.txt @@ -1,7 +1,7 @@ module type Ext = sig [%%item.extension ] - [%%item.extension.with.args "argument"] + [%%item.extension.with.args {js|argument|js}] [%%item.extension.with.args fun x -> f x] [%%item.extension ][@@withAttr ] end \ No newline at end of file diff --git a/tests/parsing/grammar/structure/expected/itemExtension.res.txt b/tests/parsing/grammar/structure/expected/itemExtension.res.txt index 15d48742..ae308fb4 100644 --- a/tests/parsing/grammar/structure/expected/itemExtension.res.txt +++ b/tests/parsing/grammar/structure/expected/itemExtension.res.txt @@ -1,5 +1,5 @@ [%%itemExtension ] [%%item.extension ] -[%%item.extension.with.args "argument"] +[%%item.extension.with.args {js|argument|js}] [%%item.extension.with.args fun x -> f x] [%%itemExtension ][@@attrOnExtension ] \ No newline at end of file diff --git a/tests/parsing/grammar/structure/expected/modExprExtension.res.txt b/tests/parsing/grammar/structure/expected/modExprExtension.res.txt index 09d750a4..88d34045 100644 --- a/tests/parsing/grammar/structure/expected/modExprExtension.res.txt +++ b/tests/parsing/grammar/structure/expected/modExprExtension.res.txt @@ -1,4 +1,4 @@ module A = [%modExprExtension ] module B = [%mod.expr.extension ] -module C = [%mod.expr.extension.with.args "argument"] +module C = [%mod.expr.extension.with.args {js|argument|js}] module D = [%mod.expr.extension.with.args fun x -> f x] \ No newline at end of file diff --git a/tests/parsing/grammar/structure/expected/moduleTypeExtension.res.txt b/tests/parsing/grammar/structure/expected/moduleTypeExtension.res.txt index f8b85d50..7b0932f9 100644 --- a/tests/parsing/grammar/structure/expected/moduleTypeExtension.res.txt +++ b/tests/parsing/grammar/structure/expected/moduleTypeExtension.res.txt @@ -1,4 +1,4 @@ module type A = [%modTypeExtension ] module type B = [%mod.type.extension ] -module type C = [%mod.type.extension.with.args "argument"] +module type C = [%mod.type.extension.with.args {js|argument|js}] module type D = [%mod.type.extension.with.args fun x -> f x] \ No newline at end of file diff --git a/tests/parsing/grammar/structure/expected/standaloneAttribute.res.txt b/tests/parsing/grammar/structure/expected/standaloneAttribute.res.txt index 86f72f08..53adcb3b 100644 --- a/tests/parsing/grammar/structure/expected/standaloneAttribute.res.txt +++ b/tests/parsing/grammar/structure/expected/standaloneAttribute.res.txt @@ -1,3 +1,3 @@ [@@@standaloneAttribute ] -[@@@standaloneAttribute "with payload"] +[@@@standaloneAttribute {js|with payload|js}] [@@@standaloneAttribute fun x -> x + 1] \ No newline at end of file diff --git a/tests/parsing/grammar/typedefinition/expected/privateTypeEquation.res.txt b/tests/parsing/grammar/typedefinition/expected/privateTypeEquation.res.txt index ed8a5d59..029b6a13 100644 --- a/tests/parsing/grammar/typedefinition/expected/privateTypeEquation.res.txt +++ b/tests/parsing/grammar/typedefinition/expected/privateTypeEquation.res.txt @@ -9,5 +9,5 @@ type nonrec t = private int -> x:((string)[@ns.namedArgLoc ]) -> float -> unit type nonrec t = private string as 'x type nonrec t = private [%ext ] -type nonrec t = private [%ext "console.log"] +type nonrec t = private [%ext {js|console.log|js}] type nonrec t = private React.element \ No newline at end of file diff --git a/tests/parsing/grammar/typexpr/expected/alias.res.txt b/tests/parsing/grammar/typexpr/expected/alias.res.txt index 0a6f8ff4..7cfd6941 100644 --- a/tests/parsing/grammar/typexpr/expected/alias.res.txt +++ b/tests/parsing/grammar/typexpr/expected/alias.res.txt @@ -11,7 +11,7 @@ type nonrec t = (int as 'r, int as 'g, int as 'b) color as 'rgb type nonrec t = (int as 'r, int as 'g, int as 'b) Color.t as 'rgb type nonrec t = [%t ] as 'extension type nonrec t = [%t.typ ] as 'extension -type nonrec t = [%ext.foo "raw"] as 'extension +type nonrec t = [%ext.foo {js|raw|js}] as 'extension type nonrec tup = ((int as 'x) * (int as 'y)) as 'tupleAlias let (t : string as 's) = () let (t : _ as 'underscore) = () @@ -26,5 +26,5 @@ let (t : (int as 'r, int as 'g, int as 'b) color as 'rgb) = () let (t : (int as 'r, int as 'g, int as 'b) Color.t as 'rgb) = () let (t : [%t ] as 'extension) = () let (t : [%t.typ ] as 'extension) = () -let (t : [%ext.foo "raw"] as 'extension) = () +let (t : [%ext.foo {js|raw|js}] as 'extension) = () let (t : ((int as 'x) * (int as 'y)) as 'tupleAlias) = () \ No newline at end of file diff --git a/tests/parsing/grammar/typexpr/expected/extension.res.txt b/tests/parsing/grammar/typexpr/expected/extension.res.txt index 06ee0977..2b992350 100644 --- a/tests/parsing/grammar/typexpr/expected/extension.res.txt +++ b/tests/parsing/grammar/typexpr/expected/extension.res.txt @@ -1,6 +1,6 @@ type nonrec t = [%typ ] type nonrec t = [%raw.typ ] -type nonrec t = [%raw.typ "existential"] +type nonrec t = [%raw.typ {js|existential|js}] let (t : [%typ ]) = x let (t : [%raw.typ ]) = x -let (t : [%raw.typ "ex"]) = x \ No newline at end of file +let (t : [%raw.typ {js|ex|js}]) = x \ No newline at end of file diff --git a/tests/parsing/grammar/typexpr/expected/objectTypeSpreading.res.txt b/tests/parsing/grammar/typexpr/expected/objectTypeSpreading.res.txt index 4ac552a2..4349bb0e 100644 --- a/tests/parsing/grammar/typexpr/expected/objectTypeSpreading.res.txt +++ b/tests/parsing/grammar/typexpr/expected/objectTypeSpreading.res.txt @@ -7,9 +7,12 @@ type nonrec t = < a ;u: int > -> unit type nonrec t = (< a ;u: int > as 'a) -> unit type nonrec t = < a ;u: int > -> < a ;v: int > -> unit type nonrec user = < name: string > -let (steve : < user ;age: int > ) = [%obj { name = "Steve"; age = 30 }] -let steve = ([%obj { name = "Steve"; age = 30 }] : < user ;age: int > ) -let steve = ((([%obj { name = "Steve"; age = 30 }] : < user ;age: int > )) +let (steve : < user ;age: int > ) = + [%obj { name = {js|Steve|js}; age = 30 }] +let steve = + ([%obj { name = {js|Steve|js}; age = 30 }] : < user ;age: int > ) +let steve = + ((([%obj { name = {js|Steve|js}; age = 30 }] : < user ;age: int > )) [@ns.braces ]) let printFullUser (steve : < user ;age: int > ) = Js.log steve let printFullUser ~user:(((user : < user ;age: int > ))[@ns.namedArgLoc ]) diff --git a/tests/parsing/infiniteLoops/expected/jsxChildren.res.txt b/tests/parsing/infiniteLoops/expected/jsxChildren.res.txt index 3894e259..16a1df19 100644 --- a/tests/parsing/infiniteLoops/expected/jsxChildren.res.txt +++ b/tests/parsing/infiniteLoops/expected/jsxChildren.res.txt @@ -21,6 +21,6 @@ type nonrec action = | AddUser ;;((string ~children:[] ())[@JSX ]) -let (a : action) = AddUser "test" +let (a : action) = AddUser {js|test|js} ;;etype ;;s = { x = ((list < i) > ([%rescript.exprhole ])) } \ No newline at end of file diff --git a/tests/parsing/infiniteLoops/expected/nonRecTypes.res.txt b/tests/parsing/infiniteLoops/expected/nonRecTypes.res.txt index 24cc9e83..a1595043 100644 --- a/tests/parsing/infiniteLoops/expected/nonRecTypes.res.txt +++ b/tests/parsing/infiniteLoops/expected/nonRecTypes.res.txt @@ -71,7 +71,7 @@ include mutable size: int ; mutable root: 'value node option ; compare: [ [%rescript.typehole ]] Js.Internal.fn } - ;;{js|Arity_2('value, 'value)], int), + ;;(({js|Arity_2('value, 'value)], int), }; }: { @@ -82,46 +82,48 @@ include ( ~size: int, ~root: option(node('value)), - ~compare: Js.Internal.fn([ | |js} + ~compare: Js.Internal.fn([ | |js}) + [@res.template ]) ;;Arity_2 (value, value) ;;int - ;;(t value) = "" - ;;"BS:6.0.1\132\149\166\190\000\000\000#\000\000\000\r\000\000\000&\000\000\000#\145\160\160A\160$size@\160\160A\160$root@\160\160A\160'compare@@" + ;;(t value) = {js||js} + ;;{js|BS:6.0.1\132\149\166\190\000\000\000#\000\000\000\r\000\000\000&\000\000\000#\145\160\160A\160$size@\160\160A\160$root@\160\160A\160'compare@@|js} external sizeSet : 'value t -> int -> unit = "size" - ;;"BS:6.0.1\132\149\166\190\000\000\000\021\000\000\000\t\000\000\000\026\000\000\000\025\176\160\160A\145@\160\160A\004\003@E\151\160$size@" - ;;[|(("use sizeGet instead or use {abstract = light} explicitly") + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\021\000\000\000\t\000\000\000\026\000\000\000\025\176\160\160A\145@\160\160A\004\003@E\151\160$size@|js} + ;;[|(({js|use sizeGet instead or use {abstract = light} explicitly|js}) [@ocaml.deprecated ])|] ;;[|((1)[@internal.arity ])|] external size : 'value t -> int = "" - ;;"BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$size@" + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$size@|js} ;;[|((1)[@internal.arity ])|] external sizeGet : 'value t -> int = "" - ;;"BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$size@" + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$size@|js} external rootSet : 'value t -> 'value node option -> unit = "root" - ;;"BS:6.0.1\132\149\166\190\000\000\000\021\000\000\000\t\000\000\000\026\000\000\000\025\176\160\160A\145@\160\160A\004\003@E\151\160$root@" - ;;[|(("use rootGet instead or use {abstract = light} explicitly") + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\021\000\000\000\t\000\000\000\026\000\000\000\025\176\160\160A\145@\160\160A\004\003@E\151\160$root@|js} + ;;[|(({js|use rootGet instead or use {abstract = light} explicitly|js}) [@ocaml.deprecated ])|] ;;[|((1)[@internal.arity ])|] external root : 'value t -> 'value node option = "" - ;;"BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$root@" + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$root@|js} ;;[|((1)[@internal.arity ])|] external rootGet : 'value t -> 'value node option = "" - ;;"BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$root@" - ;;[|(("use compareGet instead or use {abstract = light} explicitly") + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\016\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160$root@|js} + ;;[|(({js|use compareGet instead or use {abstract = light} explicitly|js}) [@ocaml.deprecated ])|] ;;[|((1)[@internal.arity ])|] external compare : 'value t -> [ [%rescript.typehole ]] Js.Internal.fn - ;;{js|Arity_2('value, 'value)], int) = + ;;(({js|Arity_2('value, 'value)], int) = "" "BS:6.0.1\132\149\166\190\000\000\000\019\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160'compare@"; [@internal.arity 1] external compareGet: - t('value) => Js.Internal.fn([ | |js} + t('value) => Js.Internal.fn([ | |js}) + [@res.template ]) ;;Arity_2 (value, value) ;;int - ;;"" - ;;"BS:6.0.1\132\149\166\190\000\000\000\019\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160'compare@" + ;;{js||js} + ;;{js|BS:6.0.1\132\149\166\190\000\000\000\019\000\000\000\007\000\000\000\020\000\000\000\019\176\160\160A\145@@A\152\160'compare@|js} end let has rbt value = (_findNode rbt (rootGet rbt) value) != None let rec minNode node = [%rescript.exprhole ] @@ -143,7 +145,7 @@ include match successor with | None -> let leaf = - createNode ~value:((Js.Internal.raw_expr "0") + createNode ~value:((Js.Internal.raw_expr {js|0|js}) [@ns.namedArgLoc ]) ~color:((Black)[@ns.namedArgLoc ]) ~height:((0.)[@ns.namedArgLoc ]) in let isLeaf = Js.Internal.fn_mk1 (fun x -> x == leaf) in diff --git a/tests/parsing/other/expected/attributes.res.txt b/tests/parsing/other/expected/attributes.res.txt index 53884806..d4aa3e7c 100644 --- a/tests/parsing/other/expected/attributes.res.txt +++ b/tests/parsing/other/expected/attributes.res.txt @@ -4,5 +4,5 @@ let x = 1[@@attr ?var when x == 1] ;;[%ext :val x : int] ;;[%ext :val x : int val y : float] -[%%ext ;;"A" - ;;"B"] \ No newline at end of file +[%%ext ;;{js|A|js} + ;;{js|B|js}] \ No newline at end of file diff --git a/tests/parsing/recovery/expression/expected/if.res.txt b/tests/parsing/recovery/expression/expected/if.res.txt index 1b62a7ba..3e4d5bcb 100644 --- a/tests/parsing/recovery/expression/expected/if.res.txt +++ b/tests/parsing/recovery/expression/expected/if.res.txt @@ -16,4 +16,4 @@ Did you forget a `{` here? -;;if foo = bar then Js.log "if-branch" else Js.log "else-branch" \ No newline at end of file +;;if foo = bar then Js.log {js|if-branch|js} else Js.log {js|else-branch|js} \ No newline at end of file diff --git a/tests/parsing/recovery/expression/expected/list.res.txt b/tests/parsing/recovery/expression/expected/list.res.txt index c8da551e..25507bff 100644 --- a/tests/parsing/recovery/expression/expected/list.res.txt +++ b/tests/parsing/recovery/expression/expected/list.res.txt @@ -32,11 +32,11 @@ let flags = ((let parts = Utils.split_on_char ' ' flags in let rec loop items = ((match items with - | [|"-pp";_ppFlag;rest|] -> loop rest + | [|{js|-pp|js};_ppFlag;rest|] -> loop rest | [|x;rest|] -> [|x;(loop rest)|] | [||] -> [||]) [@ns.braces ]) in - (loop parts) |> (String.concat " ")) + (loop parts) |> (String.concat {js| |js})) [@ns.braces ]) else flags) [@ns.ternary ]) \ No newline at end of file diff --git a/tests/parsing/recovery/string/expected/emptyeof.res.txt b/tests/parsing/recovery/string/expected/emptyeof.res.txt index 9e857f15..62f60c7d 100644 --- a/tests/parsing/recovery/string/expected/emptyeof.res.txt +++ b/tests/parsing/recovery/string/expected/emptyeof.res.txt @@ -7,4 +7,5 @@ This string is missing a double quote at the end -let x = "\n" \ No newline at end of file +let x = {js| +|js} \ No newline at end of file diff --git a/tests/parsing/recovery/string/expected/eof.res.txt b/tests/parsing/recovery/string/expected/eof.res.txt index 1d495390..3faafc64 100644 --- a/tests/parsing/recovery/string/expected/eof.res.txt +++ b/tests/parsing/recovery/string/expected/eof.res.txt @@ -7,4 +7,5 @@ This string is missing a double quote at the end -let x = "eof here\n" \ No newline at end of file +let x = {js|eof here +|js} \ No newline at end of file diff --git a/tests/parsing/recovery/string/expected/es6template.res.txt b/tests/parsing/recovery/string/expected/es6template.res.txt index 53be3098..858d46e6 100644 --- a/tests/parsing/recovery/string/expected/es6template.res.txt +++ b/tests/parsing/recovery/string/expected/es6template.res.txt @@ -7,4 +7,7 @@ Did you forget to close this template expression with a backtick? -let x = ({js|this contains |js} ^ foo) ^ {js|, missing closing|js} \ No newline at end of file +let x = + (((((({js|this contains |js})[@res.template ]) ^ foo)[@res.template ]) ^ + (({js|, missing closing|js})[@res.template ])) + [@res.template ]) \ No newline at end of file diff --git a/tests/parsing/recovery/string/expected/unclosed.res.txt b/tests/parsing/recovery/string/expected/unclosed.res.txt index 308116b1..793509c1 100644 --- a/tests/parsing/recovery/string/expected/unclosed.res.txt +++ b/tests/parsing/recovery/string/expected/unclosed.res.txt @@ -1,2 +1,2 @@ -let x = "unclosed" +let x = {js|unclosed|js} let y = 1 \ No newline at end of file diff --git a/tests/printer/expr/expected/templateLiteral.res.txt b/tests/printer/expr/expected/templateLiteral.res.txt index 445c7767..740691ac 100644 --- a/tests/printer/expr/expected/templateLiteral.res.txt +++ b/tests/printer/expr/expected/templateLiteral.res.txt @@ -9,7 +9,7 @@ let s = `multi string ` -let s = foo +let s = `${foo}` let s = `before${foo}` let s = `before ${foo}` diff --git a/tests/printer/other/char.res b/tests/printer/other/char.res index a2db5895..47ba3a53 100644 --- a/tests/printer/other/char.res +++ b/tests/printer/other/char.res @@ -9,3 +9,5 @@ let x = ' ' let x = '\o021' let x = '\xAA' let x = '\179' +let heart = '\u2665' +let smile2 = '\u{1F600}' diff --git a/tests/printer/other/expected/char.res.txt b/tests/printer/other/expected/char.res.txt index 86d1b1a3..47ba3a53 100644 --- a/tests/printer/other/expected/char.res.txt +++ b/tests/printer/other/expected/char.res.txt @@ -6,6 +6,8 @@ let x = '\t' let x = '\b' let x = '\r' let x = ' ' -let x = '\017' -let x = '\170' +let x = '\o021' +let x = '\xAA' let x = '\179' +let heart = '\u2665' +let smile2 = '\u{1F600}' diff --git a/tests/printer/other/expected/string.res.txt b/tests/printer/other/expected/string.res.txt index 79f8f27f..2c2b2fc9 100644 --- a/tests/printer/other/expected/string.res.txt +++ b/tests/printer/other/expected/string.res.txt @@ -9,3 +9,7 @@ let s = "a double escaped \\ test" let s = "what happens here \\n" let s = "\123 \o111 \xA0" + +let heart = "\u2665" + +let smile = "emoji: \u{1F600}" diff --git a/tests/printer/other/string.res b/tests/printer/other/string.res index 79f8f27f..2c2b2fc9 100644 --- a/tests/printer/other/string.res +++ b/tests/printer/other/string.res @@ -9,3 +9,7 @@ let s = "a double escaped \\ test" let s = "what happens here \\n" let s = "\123 \o111 \xA0" + +let heart = "\u2665" + +let smile = "emoji: \u{1F600}" diff --git a/tests/res_test.ml b/tests/res_test.ml index 7ca12bc6..37ef9bd4 100644 --- a/tests/res_test.ml +++ b/tests/res_test.ml @@ -177,3 +177,4 @@ end let () = OutcomePrinterTests.run() let () = ParserApiTest.run() +let () = Res_utf8_test.run() diff --git a/tests/res_utf8_test.ml b/tests/res_utf8_test.ml new file mode 100644 index 00000000..7d5172ce --- /dev/null +++ b/tests/res_utf8_test.ml @@ -0,0 +1,91 @@ +type utf8Test = { + codepoint: int; + str: string; + size: int; +} + +let utf8CodePointTests = [| + {codepoint = 0x00; str = "\x00"; size = 1}; + {codepoint = 0x01; str = "\x01"; size = 1}; + {codepoint = 0x7e; str = "\x7e"; size = 1}; + {codepoint = 0x7f; str = "\x7f"; size = 1}; + {codepoint = 0x0080; str = "\xc2\x80"; size = 2}; + {codepoint = 0x0081; str = "\xc2\x81"; size = 2}; + {codepoint = 0x00bf; str = "\xc2\xbf"; size = 2}; + {codepoint = 0x00c0; str = "\xc3\x80"; size = 2}; + {codepoint = 0x00c1; str = "\xc3\x81"; size = 2}; + {codepoint = 0x00c8; str = "\xc3\x88"; size = 2}; + {codepoint = 0x00d0; str = "\xc3\x90"; size = 2}; + {codepoint = 0x00e0; str = "\xc3\xa0"; size = 2}; + {codepoint = 0x00f0; str = "\xc3\xb0"; size = 2}; + {codepoint = 0x00f8; str = "\xc3\xb8"; size = 2}; + {codepoint = 0x00ff; str = "\xc3\xbf"; size = 2}; + {codepoint = 0x0100; str = "\xc4\x80"; size = 2}; + {codepoint = 0x07ff; str = "\xdf\xbf"; size = 2}; + {codepoint = 0x0400; str = "\xd0\x80"; size = 2}; + {codepoint = 0x0800; str = "\xe0\xa0\x80"; size = 3}; + {codepoint = 0x0801; str = "\xe0\xa0\x81"; size = 3}; + {codepoint = 0x1000; str = "\xe1\x80\x80"; size = 3}; + {codepoint = 0xd000; str = "\xed\x80\x80"; size = 3}; + {codepoint = 0xd7ff; str = "\xed\x9f\xbf"; size = 3}; + {codepoint = 0xe000; str = "\xee\x80\x80"; size = 3}; + {codepoint = 0xfffe; str = "\xef\xbf\xbe"; size = 3}; + {codepoint = 0xffff; str = "\xef\xbf\xbf"; size = 3}; + {codepoint = 0x10000; str = "\xf0\x90\x80\x80"; size = 4}; + {codepoint = 0x10001; str = "\xf0\x90\x80\x81"; size = 4}; + {codepoint = 0x40000; str = "\xf1\x80\x80\x80"; size = 4}; + {codepoint = 0x10fffe; str = "\xf4\x8f\xbf\xbe"; size = 4}; + {codepoint = 0x10ffff; str = "\xf4\x8f\xbf\xbf"; size = 4}; + {codepoint = 0xFFFD; str = "\xef\xbf\xbd"; size = 3} +|] + +let surrogateRange = [| + {codepoint = 0xFFFD; str = "\xed\xa0\x80"; size = 1}; + {codepoint = 0xFFFD; str = "\xed\xbf\xbf"; size = 1}; +|] + +let testDecode () = + Array.iter (fun t -> + let len = String.length t.str in + let (codepoint, size) = Res_utf8.decodeCodePoint 0 t.str len in + assert (codepoint = t.codepoint); + assert (size = t.size) +) utf8CodePointTests + +let testDecodeSurrogateRange () = + Array.iter (fun t -> + let len = String.length t.str in + let (codepoint, size) = Res_utf8.decodeCodePoint 0 t.str len in + assert (codepoint = t.codepoint); + assert (size = t.size) +) surrogateRange + +let testEncode () = + Array.iter (fun t -> + let encodedString = Res_utf8.encodeCodePoint t.codepoint in + assert (encodedString = t.str) +) utf8CodePointTests + +let validCodePointsTests = [| + (0, true); + (Char.code 'e', true); + (Res_utf8.max, true); + (0xD7FF, true); + (0xD800, false); + (0xDFFF, false); + (0xE000, true); + (Res_utf8.max + 1, false); + (-1, false); +|] + +let testIsValidCodePoint () = + Array.iter (fun (codePoint, t) -> + assert ((Res_utf8.isValidCodePoint codePoint) = t) + ) validCodePointsTests + +let run () = + testDecode(); + testDecodeSurrogateRange(); + testEncode(); + testIsValidCodePoint(); + print_endline "✅ utf8 tests"