diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135eeb32c05..ab0ac01faf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,7 +83,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - cache: npm - name: Copy exes to platform bin dirs run: node ./scripts/copyExes.js @@ -171,7 +170,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - cache: npm - name: Install npm packages run: npm ci --ignore-scripts @@ -282,7 +280,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - cache: npm - name: NPM install run: npm ci --ignore-scripts @@ -346,7 +343,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - cache: npm - name: Download artifacts uses: actions/download-artifact@v4 @@ -380,7 +376,6 @@ jobs: with: node-version: 18 registry-url: https://registry.npmjs.org # Needed to make auth work for publishing - cache: npm - name: Download artifacts uses: actions/download-artifact@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index e0faeef98de..e3db6c5bcab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,6 @@ - Turn off transformation for closures inside loops when capturing loop variables, now that `let` is emitted instead of `var`. https://github.com/rescript-lang/rescript-compiler/pull/6480 - Fix formatter eats comments on the first argument of a uncurried function. https://github.com/rescript-lang/rescript-compiler/pull/6763 - Fix formatter removes parens in pipe operator with anonymous uncurried function. https://github.com/rescript-lang/rescript-compiler/pull/6766 -- Allow [future reserved words in older standards](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#future_reserved_words_in_older_standards) as identifiers. https://github.com/rescript-lang/rescript-compiler/pull/6658 # 11.1.0 diff --git a/jscomp/ext/ext_ident.ml b/jscomp/ext/ext_ident.ml index 3e0d5e7915d..14b517c13df 100644 --- a/jscomp/ext/ext_ident.ml +++ b/jscomp/ext/ext_ident.ml @@ -174,19 +174,14 @@ let name_mangle name = Ext_ident.convert "^";; - : string = "$caret" ]} - [convert name] if [name] is a js keyword, and also is not explicitly used as exotic identifier, add "$$" + [convert name] if [name] is a js keyword, add "$$" otherwise do the name mangling to make sure ocaml identifier it is a valid js identifier *) let convert (name : string) = - if is_exotic name then - let name = unwrap_exotic name in - if Js_reserved_map.is_js_keyword name then "$$" ^ name - else name_mangle name - else - if Js_reserved_map.is_js_keyword name || Js_reserved_map.is_js_special_word name || Js_reserved_map.is_reserved name then - "$$" ^ name - else name_mangle name + if Js_reserved_map.is_reserved name then + "$$" ^ name + else name_mangle name (** keyword could be used in property *) diff --git a/jscomp/ext/js_reserved_map.ml b/jscomp/ext/js_reserved_map.ml index edbac3a1c94..c60bea0975b 100644 --- a/jscomp/ext/js_reserved_map.ml +++ b/jscomp/ext/js_reserved_map.ml @@ -1,3 +1,4 @@ + (* Copyright (C) 2019-Present Hongbo Zhang, Authors of ReScript * * This program is free software: you can redistribute it and/or modify @@ -22,96 +23,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -type element = string - -let rec binarySearchAux (arr : element array) (lo : int) (hi : int) key : bool = - let mid = (lo + hi)/2 in - let midVal = Array.unsafe_get arr mid in - if key = midVal then true - else if key < midVal then (* a[lo] =< key < a[mid] <= a[hi] *) - if hi = mid then - (Array.unsafe_get arr lo) = key - else binarySearchAux arr lo mid key - else (* a[lo] =< a[mid] < key <= a[hi] *) - if lo = mid then - (Array.unsafe_get arr hi) = key - else binarySearchAux arr mid hi key - -let binarySearch (key : element) (sorted : element array) : bool = - let len = Array.length sorted in - if len = 0 then false - else - let lo = Array.unsafe_get sorted 0 in - if key < lo then false - else - let hi = Array.unsafe_get sorted (len - 1) in - if key > hi then false - else binarySearchAux sorted 0 (len - 1) key - -let sorted_js_keyword = [| - "await"; - "break"; - "case"; - "catch"; - "class"; - "const"; - "continue"; - "debugger"; - "default"; - "delete"; - "do"; - "else"; - "enum"; - "export"; - "extends"; - "false"; - "finally"; - "for"; - "function"; - "if"; - "implements"; - "import"; - "in"; - "instanceof"; - "interface"; - "let"; - "new"; - "null"; - "package"; - "private"; - "protected"; - "public"; - "return"; - "static"; - "super"; - "switch"; - "this"; - "throw"; - "true"; - "try"; - "typeof"; - "var"; - "void"; - "while"; - "with"; - "yield"; - |] - -let is_js_keyword s = binarySearch s sorted_js_keyword - -let sorted_js_special_word = [| - "arguments"; - "as"; - "async"; - "eval"; - |] - -let is_js_special_word s = binarySearch s sorted_js_special_word - -let sorted_reserved = [| +let sorted_keywords = [| "AbortController"; "AbortSignal"; "AbstractRange"; + "ActiveXObject"; "AggregateError"; "AnalyserNode"; "Animation"; @@ -150,6 +66,7 @@ let sorted_reserved = [| "BiquadFilterNode"; "Blob"; "BlobEvent"; + "BluetoothUUID"; "Boolean"; "BroadcastChannel"; "BrowserCaptureMediaStreamTrack"; @@ -193,11 +110,9 @@ let sorted_reserved = [| "CSSRule"; "CSSRuleList"; "CSSScale"; - "CSSScopeRule"; "CSSSkew"; "CSSSkewX"; "CSSSkewY"; - "CSSStartingStyleRule"; "CSSStyleDeclaration"; "CSSStyleRule"; "CSSStyleSheet"; @@ -216,7 +131,6 @@ let sorted_reserved = [| "CanvasRenderingContext2D"; "ChannelMergerNode"; "ChannelSplitterNode"; - "CharacterBoundsUpdateEvent"; "CharacterData"; "ClipboardEvent"; "CloseEvent"; @@ -263,7 +177,6 @@ let sorted_reserved = [| "DocumentType"; "DragEvent"; "DynamicsCompressorNode"; - "EditContext"; "Element"; "ElementInternals"; "EncodedAudioChunk"; @@ -411,7 +324,6 @@ let sorted_reserved = [| "IntersectionObserver"; "IntersectionObserverEntry"; "Intl"; - "Iterator"; "JSON"; "KeyboardEvent"; "KeyframeEffect"; @@ -444,7 +356,6 @@ let sorted_reserved = [| "MediaStreamTrackEvent"; "MediaStreamTrackGenerator"; "MediaStreamTrackProcessor"; - "MediaStreamTrackVideoStats"; "MessageChannel"; "MessageEvent"; "MessagePort"; @@ -458,7 +369,6 @@ let sorted_reserved = [| "NamedNodeMap"; "NavigateEvent"; "Navigation"; - "NavigationActivation"; "NavigationCurrentEntryChangeEvent"; "NavigationDestination"; "NavigationHistoryEntry"; @@ -480,15 +390,15 @@ let sorted_reserved = [| "Option"; "OscillatorNode"; "OverconstrainedError"; - "PageRevealEvent"; "PageTransitionEvent"; "PannerNode"; "Path2D"; + "PaymentManager"; + "PaymentRequestUpdateEvent"; "Performance"; "PerformanceElementTiming"; "PerformanceEntry"; "PerformanceEventTiming"; - "PerformanceLongAnimationFrameTiming"; "PerformanceLongTaskTiming"; "PerformanceMark"; "PerformanceMeasure"; @@ -498,7 +408,6 @@ let sorted_reserved = [| "PerformanceObserverEntryList"; "PerformancePaintTiming"; "PerformanceResourceTiming"; - "PerformanceScriptTiming"; "PerformanceServerTiming"; "PerformanceTiming"; "PeriodicSyncManager"; @@ -671,11 +580,9 @@ let sorted_reserved = [| "SharedWorker"; "SourceBuffer"; "SourceBufferList"; - "SpeechSynthesis"; "SpeechSynthesisErrorEvent"; "SpeechSynthesisEvent"; "SpeechSynthesisUtterance"; - "SpeechSynthesisVoice"; "StaticRange"; "StereoPannerNode"; "Storage"; @@ -699,14 +606,11 @@ let sorted_reserved = [| "TextEncoder"; "TextEncoderStream"; "TextEvent"; - "TextFormat"; - "TextFormatUpdateEvent"; "TextMetrics"; "TextTrack"; "TextTrackCue"; "TextTrackCueList"; "TextTrackList"; - "TextUpdateEvent"; "TimeRanges"; "ToggleEvent"; "Touch"; @@ -776,6 +680,7 @@ let sorted_reserved = [| "WritableStream"; "WritableStreamDefaultController"; "WritableStreamDefaultWriter"; + "XDomainRequest"; "XMLDocument"; "XMLHttpRequest"; "XMLHttpRequestEventTarget"; @@ -788,38 +693,128 @@ let sorted_reserved = [| "__dirname"; "__esModule"; "__filename"; + "abstract"; + "arguments"; + "await"; + "boolean"; + "break"; + "byte"; + "case"; + "catch"; + "char"; + "class"; "clearImmediate"; "clearInterval"; "clearTimeout"; "console"; + "const"; + "continue"; + "debugger"; "decodeURI"; "decodeURIComponent"; + "default"; + "delete"; + "do"; "document"; + "double"; + "else"; "encodeURI"; "encodeURIComponent"; + "enum"; "escape"; + "eval"; "event"; + "export"; "exports"; + "extends"; + "false"; "fetch"; + "final"; + "finally"; + "float"; + "for"; + "function"; "global"; - "globalThis"; + "goto"; + "if"; + "implements"; + "import"; + "in"; + "instanceof"; + "int"; + "interface"; "isFinite"; "isNaN"; + "let"; "location"; + "long"; "module"; + "native"; "navigator"; + "new"; + "null"; + "package"; "parseFloat"; "parseInt"; + "private"; "process"; + "protected"; + "public"; "require"; - "self"; + "return"; "setImmediate"; "setInterval"; "setTimeout"; + "short"; + "static"; + "super"; + "switch"; + "synchronized"; + "this"; + "throw"; + "transient"; + "true"; + "try"; + "typeof"; "undefined"; "unescape"; + "var"; + "void"; + "volatile"; + "while"; "window"; + "with"; + "yield"; |] -let is_reserved s = binarySearch s sorted_reserved +type element = string + +let rec binarySearchAux (arr : element array) (lo : int) (hi : int) key : bool = + let mid = (lo + hi)/2 in + let midVal = Array.unsafe_get arr mid in + (* let c = cmp key midVal [@bs] in *) + if key = midVal then true + else if key < midVal then (* a[lo] =< key < a[mid] <= a[hi] *) + if hi = mid then + (Array.unsafe_get arr lo) = key + else binarySearchAux arr lo mid key + else (* a[lo] =< a[mid] < key <= a[hi] *) + if lo = mid then + (Array.unsafe_get arr hi) = key + else binarySearchAux arr mid hi key + +let binarySearch (sorted : element array) (key : element) : bool = + let len = Array.length sorted in + if len = 0 then false + else + let lo = Array.unsafe_get sorted 0 in + (* let c = cmp key lo [@bs] in *) + if key < lo then false + else + let hi = Array.unsafe_get sorted (len - 1) in + (* let c2 = cmp key hi [@bs]in *) + if key > hi then false + else binarySearchAux sorted 0 (len - 1) key + +let is_reserved s = binarySearch sorted_keywords s diff --git a/jscomp/ext/js_reserved_map.mli b/jscomp/ext/js_reserved_map.mli index 123c6a4491b..072737f89cc 100644 --- a/jscomp/ext/js_reserved_map.mli +++ b/jscomp/ext/js_reserved_map.mli @@ -22,8 +22,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -val is_js_keyword : string -> bool - -val is_js_special_word : string -> bool - val is_reserved : string -> bool diff --git a/jscomp/keywords.list b/jscomp/keywords.list index ef82abd5eee..b51740d0075 100644 --- a/jscomp/keywords.list +++ b/jscomp/keywords.list @@ -39,6 +39,7 @@ BigUint64Array BiquadFilterNode Blob BlobEvent +BluetoothUUID Boolean BroadcastChannel BrowserCaptureMediaStreamTrack @@ -80,11 +81,9 @@ CSSRotate CSSRule CSSRuleList CSSScale -CSSScopeRule CSSSkew CSSSkewX CSSSkewY -CSSStartingStyleRule CSSStyleDeclaration CSSStyleRule CSSStyleSheet @@ -103,7 +102,6 @@ CanvasPattern CanvasRenderingContext2D ChannelMergerNode ChannelSplitterNode -CharacterBoundsUpdateEvent CharacterData ClipboardEvent CloseEvent @@ -149,7 +147,6 @@ DocumentTimeline DocumentType DragEvent DynamicsCompressorNode -EditContext Element ElementInternals EncodedAudioChunk @@ -297,7 +294,6 @@ Int8Array IntersectionObserver IntersectionObserverEntry Intl -Iterator JSON KeyboardEvent KeyframeEffect @@ -330,7 +326,6 @@ MediaStreamTrack MediaStreamTrackEvent MediaStreamTrackGenerator MediaStreamTrackProcessor -MediaStreamTrackVideoStats MessageChannel MessageEvent MessagePort @@ -344,7 +339,6 @@ NaN NamedNodeMap NavigateEvent Navigation -NavigationActivation NavigationCurrentEntryChangeEvent NavigationDestination NavigationHistoryEntry @@ -366,15 +360,15 @@ OffscreenCanvasRenderingContext2D Option OscillatorNode OverconstrainedError -PageRevealEvent PageTransitionEvent PannerNode Path2D +PaymentManager +PaymentRequestUpdateEvent Performance PerformanceElementTiming PerformanceEntry PerformanceEventTiming -PerformanceLongAnimationFrameTiming PerformanceLongTaskTiming PerformanceMark PerformanceMeasure @@ -384,7 +378,6 @@ PerformanceObserver PerformanceObserverEntryList PerformancePaintTiming PerformanceResourceTiming -PerformanceScriptTiming PerformanceServerTiming PerformanceTiming PeriodicSyncManager @@ -557,11 +550,9 @@ ShadowRoot SharedWorker SourceBuffer SourceBufferList -SpeechSynthesis SpeechSynthesisErrorEvent SpeechSynthesisEvent SpeechSynthesisUtterance -SpeechSynthesisVoice StaticRange StereoPannerNode Storage @@ -585,14 +576,11 @@ TextDecoderStream TextEncoder TextEncoderStream TextEvent -TextFormat -TextFormatUpdateEvent TextMetrics TextTrack TextTrackCue TextTrackCueList TextTrackList -TextUpdateEvent TimeRanges ToggleEvent Touch diff --git a/scripts/build_reserved.ml b/scripts/build_reserved.ml index 1eec96ebe2f..6e5103a1e99 100644 --- a/scripts/build_reserved.ml +++ b/scripts/build_reserved.ml @@ -22,148 +22,142 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -module SSet = Set.Make (String) - -(* Words that can never be identifier's name - See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_words -*) -let js_keywords = - SSet.of_list - [ - "break"; - "case"; - "catch"; - "class"; - "const"; - "continue"; - "debugger"; - "default"; - "delete"; - "do"; - "else"; - "export"; - "extends"; - "false"; - "finally"; - "for"; - "function"; - "if"; - "import"; - "in"; - "instanceof"; - "new"; - "null"; - "return"; - "super"; - "switch"; - "this"; - "throw"; - "true"; - "try"; - "typeof"; - "var"; - "void"; - "while"; - "with"; - (* The following are also reserved in strict context, including ESM *) - "let"; - "static"; - "yield"; - (* `await` is reserved in async context, including ESM *) - "await"; - (* Future reserved words *) - "enum"; - "implements"; - "interface"; - "package"; - "private"; - "protected"; - "public"; - ] - -(* Identifiers with special meanings - See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers_with_special_meanings - - They can have different meanings depending on the context when used as identifier names, so it should be done carefully. -*) -let js_special_words = - SSet.of_list - [ - "arguments"; - "as"; - "async"; - "eval"; - (* However, some of these are actually used with no problems today. - Preventing this can be annoying. *) - (* - "from"; - "get"; - "of"; - "set"; - *) - ] - -(* Other identifier names should be care about *) -let reserved_words = - SSet.of_list - [ - (* Reserved for common globals *) - "undefined"; - "self"; - "globalThis"; - "console"; - "setTimeout"; - "setInterval"; - "clearTimeout"; - "clearInterval"; - "decodeURI"; - "decodeURIComponent"; - "encodeURI"; - "encodeURIComponent"; - "escape"; - "unescape"; - "fetch"; - "isNaN"; - "isFinite"; - "parseFloat"; - "parseInt"; - (* Reserved for common DOM globals *) - "event"; - "window"; - "document"; - "location"; - "navigator"; - (* Reserved for common Node.js globals *) - "Buffer"; - "setImmediate"; - "clearImmediate"; - "global"; - "process"; - "require"; - "module"; - "exports"; - "__dirname"; - "__filename"; - "__esModule"; - (* Bun global obj *) - "Bun"; - (* Deno global obj *) - "Deno"; - ] - -let get_predefined_words (fn : string) = - let v = ref SSet.empty in - let in_chan = open_in_bin fn in + let reserved_words = + [| + (* keywords *) + "break"; + "case"; "catch"; "continue"; + "debugger";"default";"delete";"do"; + "else"; + "finally";"for";"function"; + "if"; (* "then"; *) "in";"instanceof"; + "new"; + "return"; + "switch"; + "this"; "throw"; "try"; "typeof"; + "var"; "void"; "while"; "with"; + + (* reserved in ECMAScript 5 *) + "class"; "enum"; "export"; "extends"; "import"; "super"; + + "implements";"interface"; + "let"; + "package";"private";"protected";"public"; + "static"; + "yield"; + + (* other *) + "null"; + "true"; + "false"; + "NaN"; + + + "undefined"; + "this"; + + (* also reserved in ECMAScript 3 *) + "abstract"; "boolean"; "byte"; "char"; "const"; "double"; + "final"; "float"; "goto"; "int"; "long"; "native"; "short"; + "synchronized"; + (* "throws"; *) + (* seems to be fine, like nodejs [assert.throws] *) + "transient"; "volatile"; + + (* also reserved in ECMAScript 6 *) + "await"; + + "event"; + "location"; + "window"; + "document"; + "eval"; + "navigator"; + (* "self"; *) + + "Array"; + "Date"; + "Math"; + "JSON"; + "Object"; + "RegExp"; + "String"; + "Boolean"; + "Number"; + "Buffer"; (* Node *) + "Map"; (* es6*) + "Set"; + "Promise"; + "Infinity"; + "isFinite"; + + "ActiveXObject"; + "XMLHttpRequest"; + "XDomainRequest"; + + "DOMException"; + "Error"; + "SyntaxError"; + "arguments"; + + "decodeURI"; + "decodeURIComponent"; + "encodeURI"; + "encodeURIComponent"; + "escape"; + "unescape"; + "fetch"; + "isNaN"; + "parseFloat"; + "parseInt"; + + (** reserved for commonjs and NodeJS globals*) + "require"; + "exports"; + "module"; + "clearImmediate"; + "clearInterval"; + "clearTimeout"; + "console"; + "global"; + "process"; + "require"; + "setImmediate"; + "setInterval"; + "setTimeout"; + "__dirname"; + "__filename"; + "__esModule"; + + (* Bun global obj *) + "Bun"; + + (* Deno global obj *) + "Deno"; + |] + + +module SSet = Set.Make(String) +let get_predefined_words (fn : string) = + let v = ref SSet.empty in + let in_chan = open_in_bin fn in (try - while true do - let new_word = input_line in_chan in - if String.length new_word <> 0 then v := SSet.add new_word !v - done + while true do + let new_word = input_line in_chan in + if String.length new_word <> 0 then + v := SSet.add new_word !v + done with End_of_file -> ()); - !v + !v -let license = - {|(* Copyright (C) 2019-Present Hongbo Zhang, Authors of ReScript +let fill_extra (ss : SSet.t) : SSet.t = + let v = ref ss in + for i = 0 to Array.length reserved_words - 1 do + v := SSet.add reserved_words.(i) !v + done; + !v +let license = {| +(* Copyright (C) 2019-Present Hongbo Zhang, Authors of ReScript * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -188,58 +182,58 @@ let license = * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) |} +let binary_search = {| -let binary_search = - {|type element = string - -let rec binarySearchAux (arr : element array) (lo : int) (hi : int) key : bool = - let mid = (lo + hi)/2 in - let midVal = Array.unsafe_get arr mid in - if key = midVal then true - else if key < midVal then (* a[lo] =< key < a[mid] <= a[hi] *) - if hi = mid then - (Array.unsafe_get arr lo) = key - else binarySearchAux arr lo mid key - else (* a[lo] =< a[mid] < key <= a[hi] *) - if lo = mid then - (Array.unsafe_get arr hi) = key - else binarySearchAux arr mid hi key - -let binarySearch (key : element) (sorted : element array) : bool = - let len = Array.length sorted in +type element = string + +let rec binarySearchAux (arr : element array) (lo : int) (hi : int) key : bool = + let mid = (lo + hi)/2 in + let midVal = Array.unsafe_get arr mid in + (* let c = cmp key midVal [@bs] in *) + if key = midVal then true + else if key < midVal then (* a[lo] =< key < a[mid] <= a[hi] *) + if hi = mid then + (Array.unsafe_get arr lo) = key + else binarySearchAux arr lo mid key + else (* a[lo] =< a[mid] < key <= a[hi] *) + if lo = mid then + (Array.unsafe_get arr hi) = key + else binarySearchAux arr mid hi key + +let binarySearch (sorted : element array) (key : element) : bool = + let len = Array.length sorted in if len = 0 then false - else - let lo = Array.unsafe_get sorted 0 in + else + let lo = Array.unsafe_get sorted 0 in + (* let c = cmp key lo [@bs] in *) if key < lo then false else - let hi = Array.unsafe_get sorted (len - 1) in - if key > hi then false - else binarySearchAux sorted 0 (len - 1) key + let hi = Array.unsafe_get sorted (len - 1) in + (* let c2 = cmp key hi [@bs]in *) + if key > hi then false + else binarySearchAux sorted 0 (len - 1) key +let is_reserved s = binarySearch sorted_keywords s |} - -let make_predicate tag ss = - let array_ident = "sorted_" ^ tag in - let array = - SSet.fold - (fun s acc -> acc ^ "\"" ^ s ^ "\";\n ") - ss - ("let " ^ array_ident ^ " = [|\n ") - ^ "|]" - in - let fn_ident = "is_" ^ tag in - let fn = "let " ^ fn_ident ^ " s = binarySearch s " ^ array_ident in - array ^ "\n\n" ^ fn ^ "\n\n" - -let main words_file output_file = - let predefined_words = get_predefined_words words_file in - let predefined_words = SSet.union predefined_words reserved_words in - let oc = open_out_bin output_file in - output_string oc license; +let main keyword_file output_file = + let ss = get_predefined_words keyword_file in + let ss = fill_extra ss in + let keywords_array = + (SSet.fold + (fun s acc -> acc ^ "\"" ^ s ^ "\";\n " + ) ss "let sorted_keywords = [|\n ") ^ "|]\n" + in + let oc = open_out_bin output_file in + output_string oc license ; + output_string oc keywords_array; output_string oc binary_search; - output_string oc (make_predicate "js_keyword" js_keywords); - output_string oc (make_predicate "js_special_word" js_special_words); - output_string oc (make_predicate "reserved" predefined_words); - close_out oc - + close_out oc +(* +;; +for i = 0 to Array.length Sys.argv - 1 do + print_endline ">"; print_string Sys.argv.(i) +done +;; *) let () = main Sys.argv.(1) Sys.argv.(2) + +