├── Infrared.opam ├── InfraredUtils.opam ├── InfraredCompiler.opam ├── InfraredParser.opam ├── InfraredServer.opam ├── InfraredServer └── Server.ml ├── .gitattributes ├── dune-project ├── InfraredParser ├── flow_parser │ ├── flow_parser.opam │ ├── dune-project │ ├── dune-ignore │ ├── .gitignore │ ├── lib │ │ ├── _tags │ │ ├── META │ │ ├── dune │ │ ├── translator_intf.ml │ │ ├── ast_utils.mli │ │ ├── opam │ │ ├── .merlin │ │ ├── yarn.lock │ │ ├── loc.mli │ │ ├── lex_result.ml │ │ ├── flow_parser_dot_js.ml │ │ ├── README.md │ │ ├── token_translator.ml │ │ ├── ast_utils.ml │ │ ├── pattern_cover.ml │ │ ├── file_key.ml │ │ ├── lex_env.ml │ │ ├── libflowparser.ml │ │ ├── libflowparser.h │ │ ├── loc.ml │ │ ├── flow_parser_js.ml │ │ ├── Makefile │ │ ├── parser_common.ml │ │ ├── parser_env.mli │ │ ├── token.ml │ │ ├── jsx_parser.ml │ │ └── declaration_parser.ml │ ├── bin │ │ ├── dune │ │ ├── test_flow_parser.ml │ │ └── .merlin │ ├── Makefile │ ├── package.json │ ├── README.md │ ├── LICENSE │ └── flow_parser.install ├── dune ├── Parser.ml ├── parsers │ ├── Flow │ │ ├── FlowParser.ml │ │ └── FlowError.ml │ └── ast.ml ├── TypePrinter.ml ├── .merlin └── Printer.ml ├── .vscode └── settings.json ├── tests ├── mock-project │ ├── package.json │ ├── file_0-2.js │ ├── dir1 │ │ ├── file_1-1.js │ │ └── file_1-2.js │ └── file_0-1.js ├── experiment.js └── mock-react-project │ └── file_0-1.js ├── meta ├── logo_v2.png ├── logo_v3.png └── logo_v2_smaller.png ├── assets ├── logo-old.png ├── logo-dark.png ├── logo-light.png ├── logo-alt-dark.png ├── logo-alt-light.png └── logo-round-dark.png ├── .travis.yml ├── InfraredUtils ├── dune ├── Settings.ml ├── Logger.ml ├── .merlin ├── Fs.ml ├── Utils.ml └── Chalk.ml ├── Infrared ├── commands │ ├── flag.mli │ ├── flag.ml │ ├── command.mli │ ├── command.ml │ ├── version_command.ml │ ├── help_command.ml │ ├── parse_command.ml │ └── check_command.ml ├── dune ├── main.ml ├── cli.ml └── .merlin ├── InfraredCompiler ├── dune ├── transformers │ ├── remove_assignify.ml │ ├── initialize_function_declarations.ml │ ├── function_returns_refinement.ml │ ├── typify.ml │ ├── realign_typed_expressions.ml │ └── uniquify.ml ├── Compiler.ml └── .merlin ├── .merlin ├── .gitignore ├── .editorconfig ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── CODE_OF_CONDUCT.md ├── .gitmodules ├── LICENSE ├── Makefile ├── test-coverage └── Parser │ └── run.sh └── README.md /Infrared.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /InfraredUtils.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /InfraredCompiler.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /InfraredParser.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /InfraredServer.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /InfraredServer/Server.ml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.2.1) 2 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/flow_parser.opam: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /InfraredParser/flow_parser/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.2) 2 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/dune-ignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | flow 4 | -------------------------------------------------------------------------------- /tests/mock-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mock-project" 3 | } 4 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | flow 3 | _build 4 | -------------------------------------------------------------------------------- /meta/logo_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/meta/logo_v2.png -------------------------------------------------------------------------------- /meta/logo_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/meta/logo_v3.png -------------------------------------------------------------------------------- /assets/logo-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-old.png -------------------------------------------------------------------------------- /assets/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-dark.png -------------------------------------------------------------------------------- /assets/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-light.png -------------------------------------------------------------------------------- /assets/logo-alt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-alt-dark.png -------------------------------------------------------------------------------- /meta/logo_v2_smaller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/meta/logo_v2_smaller.png -------------------------------------------------------------------------------- /assets/logo-alt-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-alt-light.png -------------------------------------------------------------------------------- /assets/logo-round-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickzuber/infrared/HEAD/assets/logo-round-dark.png -------------------------------------------------------------------------------- /tests/mock-project/file_0-2.js: -------------------------------------------------------------------------------- 1 | const add1 = n => n + 1; 2 | 3 | void add1(1, 2, 3, 4); 4 | 5 | +add1(/[*.]+/gi) 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | sudo: required 3 | 4 | language: c 5 | 6 | script: 7 | - brew install coq 8 | - bash -ex travis-ci.sh 9 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/_tags: -------------------------------------------------------------------------------- 1 | true: package(sedlex), package(wtf8) 2 | : warn(-39) 3 | : -traverse 4 | -------------------------------------------------------------------------------- /InfraredUtils/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name InfraredUtils) 3 | (public_name InfraredUtils) 4 | (libraries Str flow_parser)) 5 | -------------------------------------------------------------------------------- /Infrared/commands/flag.mli: -------------------------------------------------------------------------------- 1 | type t = { 2 | name: string; 3 | doc: string; 4 | } 5 | 6 | val create : name:string -> doc:string -> t 7 | -------------------------------------------------------------------------------- /tests/mock-project/dir1/file_1-1.js: -------------------------------------------------------------------------------- 1 | function foo (x) { 2 | return x + 1; 3 | } 4 | 5 | const y = 1; 6 | const x = foo(2); 7 | const z = x + y; 8 | -------------------------------------------------------------------------------- /Infrared/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs unqualified) 2 | 3 | (executable 4 | (name main) 5 | (libraries core unix InfraredParser InfraredCompiler InfraredUtils)) 6 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/bin/dune: -------------------------------------------------------------------------------- 1 | 2 | (executable 3 | (name test_flow_parser) 4 | (public_name test_flow_parser.exe) 5 | (libraries flow_parser)) 6 | 7 | -------------------------------------------------------------------------------- /tests/mock-project/file_0-1.js: -------------------------------------------------------------------------------- 1 | const foo = 'bar'; 2 | let bar = 1, baz = 2; 3 | var obj = { 4 | a: 1, 5 | b: 'bar' 6 | }; 7 | const {a, ...rest} = obj; 8 | -------------------------------------------------------------------------------- /tests/experiment.js: -------------------------------------------------------------------------------- 1 | let count = null; 2 | const foo = addFive(6); 3 | 4 | function addFive (n) { 5 | const five = 5; 6 | count = 500; 7 | return n + five; 8 | } 9 | -------------------------------------------------------------------------------- /Infrared/commands/flag.ml: -------------------------------------------------------------------------------- 1 | type t = { 2 | name: string; 3 | doc: string; 4 | } 5 | 6 | let create ~name ~doc = 7 | { name = name 8 | ; doc = doc 9 | } 10 | -------------------------------------------------------------------------------- /InfraredParser/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs unqualified) 2 | 3 | (library 4 | (name InfraredParser) 5 | (public_name InfraredParser) 6 | (libraries InfraredUtils core flow_parser)) 7 | -------------------------------------------------------------------------------- /InfraredCompiler/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs unqualified) 2 | 3 | (library 4 | (name InfraredCompiler) 5 | (public_name InfraredCompiler) 6 | (libraries InfraredParser InfraredUtils core)) 7 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/META: -------------------------------------------------------------------------------- 1 | name="parser_flow" 2 | version="0.70.0" 3 | description="flow parser ocamlfind package" 4 | archive(byte)="parser_flow.cma" 5 | archive(native)="parser_flow.cmxa" 6 | -------------------------------------------------------------------------------- /.merlin: -------------------------------------------------------------------------------- 1 | S Infrared/** 2 | S InfraredCompiler/** 3 | S InfraredParser/** 4 | S InfraredServer/** 5 | S InfraredUtils/** 6 | 7 | B _build/** 8 | 9 | PKG core batteries flow_parser ppx_deriving.show yojson 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Builds & Scripts 2 | _build 3 | *.native 4 | *.exe 5 | *.pyc 6 | *.failed 7 | __reports__ 8 | 9 | # Others 10 | .DS_Store 11 | .!* 12 | node_modules 13 | 14 | # Coq 15 | *.glob 16 | *.aux 17 | *.vo 18 | -------------------------------------------------------------------------------- /Infrared/commands/command.mli: -------------------------------------------------------------------------------- 1 | type t = { 2 | name: string; 3 | aliases: string list; 4 | doc: string; 5 | flags: Flag.t list 6 | } 7 | 8 | val create : name:string -> aliases:string list -> doc:string -> flags:Flag.t list -> t 9 | -------------------------------------------------------------------------------- /InfraredUtils/Settings.ml: -------------------------------------------------------------------------------- 1 | (* We print the intermediate steps and data structures when in debug mode. *) 2 | let debug_mode = ref false 3 | 4 | (* We print the inferred types in the console for each identifier in each file. *) 5 | let show_types_in_console = ref false 6 | -------------------------------------------------------------------------------- /Infrared/commands/command.ml: -------------------------------------------------------------------------------- 1 | type t = { 2 | name: string; 3 | aliases: string list; 4 | doc: string; 5 | flags: Flag.t list; 6 | } 7 | 8 | let create ~name ~aliases ~doc ~flags = 9 | { name = name 10 | ; aliases = aliases 11 | ; doc = doc 12 | ; flags = flags 13 | } 14 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name Flow_parser) 3 | (public_name flow_parser) 4 | (libraries sedlex wtf8) 5 | (modules (:standard \ ("flow_parser_js" "flow_parser_dot_js"))) 6 | (preprocess (pps sedlex.ppx)) 7 | (flags (:standard (-w -39))) 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | root = true 3 | 4 | # Basic formatting 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.js] 16 | trim_trailing_whitespace = true 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Bug Fix 2 | ------- 3 | 4 | Make sure to include a short description of what this pull request does and what problems it solves. 5 | 6 | If this pull request closes any issues, please make sure to address this by remembering to include `Closes #[ISSUE NUMBER]` at the bottom of the description. 7 | 8 | Thank you! 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "__new-infrared__/__new-infrared__/InfraredParser/flow_parser"] 2 | path = __new-infrared__/__new-infrared__/InfraredParser/flow_parser 3 | url = https://github.com/nickzuber/flow_parser 4 | [submodule "__new-infrared__/InfraredParser/flow_parser"] 5 | path = __new-infrared__/InfraredParser/flow_parser 6 | url = https://github.com/nickzuber/flow_parser 7 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean build 2 | 3 | FLOW_VERSION = 0.70.0 4 | 5 | clean: 6 | @rm -rf flow _build node_modules 7 | 8 | flow: 9 | @git clone git@github.com:facebook/flow.git 10 | @cd flow && git checkout v$(FLOW_VERSION) 11 | 12 | install: 13 | @esy install 14 | 15 | build: install 16 | @esy build 17 | 18 | test: build 19 | @esy x test_flow_parser.exe 20 | -------------------------------------------------------------------------------- /Infrared/main.ml: -------------------------------------------------------------------------------- 1 | open Cli 2 | open InfraredUtils 3 | open InfraredParser.Parser 4 | 5 | let () = 6 | try 7 | InfraredShell.exec () 8 | with 9 | | Infrared_parsing_error (count, message) -> 10 | let summary = Printf.sprintf "Failed w/ %n error(s) found" count in 11 | Printf.printf "\n%s\n%s\n\n" 12 | (summary |> Chalk.red |> Chalk.bold) 13 | message 14 | | _ -> 15 | print_endline "Infrared: Uncaught error occurred." 16 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/translator_intf.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | module type S = sig 9 | type t 10 | val string: string -> t 11 | val bool: bool -> t 12 | val obj: (string * t) list -> t 13 | val array: t list -> t 14 | val number: float -> t 15 | val null: t 16 | val regexp: Loc.t -> string -> string -> t 17 | end 18 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/ast_utils.mli: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | type binding = Loc.t * string 9 | 10 | val bindings_of_pattern: 11 | binding list -> 12 | Loc.t Ast.Pattern.t' -> 13 | binding list 14 | 15 | val bindings_of_variable_declarations: 16 | Loc.t Ast.Statement.VariableDeclaration.Declarator.t list -> 17 | binding list 18 | 19 | val partition_directives: 20 | Loc.t Ast.Statement.t list -> 21 | Loc.t Ast.Statement.t list * Loc.t Ast.Statement.t list 22 | -------------------------------------------------------------------------------- /InfraredUtils/Logger.ml: -------------------------------------------------------------------------------- 1 | module FlowAst = Flow_parser.Ast 2 | module Loc = Flow_parser.Loc 3 | 4 | let warn (msg : string) (loc : Loc.t) : unit = 5 | Printf.printf "%s %s %s\n" 6 | (" ⚠" |> Chalk.yellow |> Chalk.bold) 7 | ((Printf.sprintf "(%d:%d)" loc.start.line loc._end.column) |> Chalk.gray) 8 | msg 9 | 10 | let error (msg : string) (loc : Loc.t) : unit = 11 | Printf.printf "%s %s %s\n" 12 | (" ⃠ " |> Chalk.red |> Chalk.bold) 13 | ((Printf.sprintf "(%d:%d)" loc.start.line loc._end.column) |> Chalk.gray) 14 | msg 15 | 16 | let error_no_loc (msg : string) : unit = 17 | Printf.printf "%s (?:?) %s\n" 18 | (" ⃠ " |> Chalk.red |> Chalk.bold) 19 | msg 20 | -------------------------------------------------------------------------------- /Infrared/commands/version_command.ml: -------------------------------------------------------------------------------- 1 | let version = "0.0.1" 2 | 3 | let get_version () = 4 | let git_hash_command = "git rev-parse --short HEAD" in 5 | let version_hash = ref "" in 6 | let chan = Unix.open_process_in git_hash_command in 7 | version_hash := (input_line chan); 8 | let _ = Unix.close_process_in chan in 9 | version ^ "-" ^ !version_hash 10 | 11 | let spec = Command.create 12 | ~name:"version" 13 | ~aliases:["-v"; "--version"] 14 | ~doc:"Print the installed version of Infrared" 15 | ~flags:[] 16 | 17 | let exec = get_version 18 | 19 | type t = 20 | { spec: Command.t 21 | ; exec: unit -> string 22 | } 23 | 24 | let command : t = 25 | { spec = spec 26 | ; exec = exec 27 | } 28 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/opam: -------------------------------------------------------------------------------- 1 | opam-version: "1.2" 2 | name: "flow_parser" 3 | version: "0.70.0" 4 | maintainer: "gabe@fb.com" 5 | authors: [ 6 | "Avik Chaudhuri" 7 | "Basil Hosmer" 8 | "Gabe Levi" 9 | "Jeff Morrison" 10 | "Marshall Roch" 11 | "Sam Goldman" 12 | "James Kyle" 13 | ] 14 | homepage: "https://github.com/facebook/flow/tree/master/src/parser" 15 | bug-reports: "https://github.com/facebook/flow/issues" 16 | license: "MIT" 17 | 18 | build: [ "sh" "-c" "cd src/parser && make ocamlfind-install" ] 19 | 20 | remove: ["ocamlfind" "remove" "flow_parser"] 21 | depends: [ 22 | "ocamlfind" {build} 23 | "ocamlbuild" {build} 24 | "sedlex" 25 | "wtf8" 26 | ] 27 | available: [ocaml-version >= "4.03.0"] 28 | dev-repo: "https://github.com/facebook/flow.git" 29 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/.merlin: -------------------------------------------------------------------------------- 1 | EXCLUDE_QUERY_DIR 2 | B /Users/nick/.opam/4.08.0/lib/bytes 3 | B /Users/nick/.opam/4.08.0/lib/gen 4 | B /Users/nick/.opam/4.08.0/lib/sedlex 5 | B /Users/nick/.opam/4.08.0/lib/uchar 6 | B /Users/nick/.opam/4.08.0/lib/wtf8 7 | B ../../../_build/default/InfraredParser/flow_parser/lib/.Flow_parser.objs/byte 8 | S /Users/nick/.opam/4.08.0/lib/bytes 9 | S /Users/nick/.opam/4.08.0/lib/gen 10 | S /Users/nick/.opam/4.08.0/lib/sedlex 11 | S /Users/nick/.opam/4.08.0/lib/uchar 12 | S /Users/nick/.opam/4.08.0/lib/wtf8 13 | S . 14 | FLG -ppx '/Users/nick/projects/infrared/_build/default/.ppx/47692aba660b9b6d52b3643959b707ed/ppx.exe --as-ppx --cookie '\''library-name="Flow_parser"'\''' 15 | FLG -open Flow_parser -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs -w -39 16 | -------------------------------------------------------------------------------- /InfraredUtils/.merlin: -------------------------------------------------------------------------------- 1 | EXCLUDE_QUERY_DIR 2 | B /Users/nick/.opam/4.08.0/lib/bytes 3 | B /Users/nick/.opam/4.08.0/lib/gen 4 | B /Users/nick/.opam/4.08.0/lib/ocaml 5 | B /Users/nick/.opam/4.08.0/lib/sedlex 6 | B /Users/nick/.opam/4.08.0/lib/uchar 7 | B /Users/nick/.opam/4.08.0/lib/wtf8 8 | B ../_build/default/InfraredParser/flow_parser/lib/.Flow_parser.objs/byte 9 | B ../_build/default/InfraredUtils/.InfraredUtils.objs/byte 10 | S /Users/nick/.opam/4.08.0/lib/bytes 11 | S /Users/nick/.opam/4.08.0/lib/gen 12 | S /Users/nick/.opam/4.08.0/lib/ocaml 13 | S /Users/nick/.opam/4.08.0/lib/sedlex 14 | S /Users/nick/.opam/4.08.0/lib/uchar 15 | S /Users/nick/.opam/4.08.0/lib/wtf8 16 | S ../InfraredParser/flow_parser/lib 17 | S . 18 | FLG -open InfraredUtils -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs 19 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ast-types@0.8.18: 6 | version "0.8.18" 7 | resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.18.tgz#c8b98574898e8914e9d8de74b947564a9fe929af" 8 | 9 | colors@>=0.6.2: 10 | version "1.1.2" 11 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 12 | 13 | esprima-fb@15001.1001.0-dev-harmony-fb: 14 | version "15001.1001.0-dev-harmony-fb" 15 | resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" 16 | 17 | minimist@>=0.2.0: 18 | version "1.2.0" 19 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 20 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fastpack/flow_parser", 3 | "version": "0.70.0", 4 | "description": "Fastpack-specific package for flow_parser", 5 | "license": "MIT", 6 | "esy": { 7 | "build": [ 8 | [ 9 | "dune", 10 | "build", 11 | "-p", 12 | "flow_parser" 13 | ] 14 | ], 15 | "install": [ 16 | "esy-installer" 17 | ], 18 | "buildsInSource": "_build" 19 | }, 20 | "dependencies": { 21 | "@opam/sedlex": "*", 22 | "@opam/wtf8": "*", 23 | "@esy-ocaml/esy-installer": "^0.0.0", 24 | "@opam/dune": "*", 25 | "@opam/ocaml-migrate-parsetree": "*", 26 | "@opam/ppx_tools_versioned": "5.2" 27 | }, 28 | "peerDependencies": { 29 | "ocaml": ">= 4.3.0" 30 | }, 31 | "devDependencies": { 32 | "@esy-ocaml/merlin": "*", 33 | "ocaml": "~4.6.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/bin/test_flow_parser.ml: -------------------------------------------------------------------------------- 1 | 2 | 3 | let () = 4 | let parse_source ~types_in_comments source = 5 | let parse_options = Some Flow_parser.Parser_env.({ 6 | esproposal_optional_chaining = false; 7 | esproposal_class_instance_fields = true; 8 | esproposal_class_static_fields = true; 9 | esproposal_decorators = true; 10 | esproposal_export_star_as = true; 11 | types = true; 12 | types_in_comments; 13 | use_strict = false; 14 | }) 15 | in 16 | Flow_parser.Parser_flow.program source ~parse_options 17 | in 18 | let source = "let x = 1; /* : */" in 19 | let _ = parse_source ~types_in_comments:false source in 20 | print_endline "types_in_comments=false: OK"; 21 | let () = try 22 | parse_source ~types_in_comments:true source |> ignore 23 | with 24 | | Flow_parser.Parse_error.Error _ -> 25 | print_endline "types_in_comments=true: OK"; 26 | in 27 | () 28 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/loc.mli: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | type position = { line : int; column : int; offset : int; } 9 | type t = { source : File_key.t option; start : position; _end : position; } 10 | val none : t 11 | val btwn : t -> t -> t 12 | val btwn_exclusive : t -> t -> t 13 | val char_before : t -> t 14 | val first_char: t -> t 15 | val contains : t -> t -> bool 16 | val lines_intersect : t -> t -> bool 17 | val pos_cmp : position -> position -> int 18 | val span_compare : t -> t -> int 19 | val compare : t -> t -> int 20 | val equal : t -> t -> bool 21 | val to_string : ?include_source:bool -> t -> string 22 | val source : t -> File_key.t option 23 | (* filename, line, column. produces a Loc.t at the given location, with stubbed out offsets *) 24 | val make: File_key.t -> int -> int -> t 25 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | Roadmap for Infrared 3 | -------------------- 4 | 5 | Currently working on: 6 | 7 | ``` 8 | Lexer -> Parser -> Type System 9 | ^^^^^^ 10 | ``` 11 | 12 | Setting Up your Environment 13 | --------------------------- 14 | 15 | Have OCaml and Opam. 16 | 17 | Build executable with `make infrared` 18 | 19 | Test with `make test` 20 | 21 | Build tests with `make generate-tests`. Be very careful using this, we don't want to make tests that aren't accurate. 22 | 23 | 24 | Reporting Bugs 25 | -------------- 26 | 27 | Please reference the [issue template](https://github.com/nickzuber/infrared/blob/master/.github/ISSUE_TEMPLATE). 28 | 29 | 30 | Contributing Pull Requests 31 | -------------------------- 32 | 33 | Please reference the [pull request template](https://github.com/nickzuber/infrared/blob/master/.github/PULL_REQUEST_TEMPLATE). 34 | 35 | 36 | Final Notes 37 | ----------- 38 | 39 | I will be actually adding meaningful content to this file later. Sorry. 40 | 41 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/lex_result.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | 9 | type t = { 10 | lex_token: Token.t; 11 | lex_loc: Loc.t; 12 | lex_errors: (Loc.t * Parse_error.t) list; 13 | lex_comments: Loc.t Ast.Comment.t list; 14 | } 15 | 16 | let token result = result.lex_token 17 | let loc result = result.lex_loc 18 | let comments result = result.lex_comments 19 | let errors result = result.lex_errors 20 | 21 | let debug_string_of_lex_result lex_result = 22 | Printf.sprintf 23 | "{\n \ 24 | lex_token = %s\n \ 25 | lex_value = %S\n \ 26 | lex_errors = (length = %d)\n \ 27 | lex_comments = (length = %d)\n\ 28 | }" 29 | (Token.token_to_string lex_result.lex_token) 30 | (Token.value_of_token lex_result.lex_token) 31 | (List.length lex_result.lex_errors) 32 | (List.length lex_result.lex_comments) 33 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/README.md: -------------------------------------------------------------------------------- 1 | # flow_parser 2 | Flow parser with Fastpack-specific modifications 3 | 4 | # Upgrading the Flow version 5 | 6 | Change version in the `Makefile` and `package.json` and run: 7 | ```bash 8 | $ make clean && make flow 9 | ``` 10 | 11 | Copy the parser code to `lib/`: 12 | ```bash 13 | $ cp -R flow/src/parser/* lib 14 | ``` 15 | 16 | Manually modify `lib/parser_env.mli`: 17 | ``` 18 | 36a37 19 | + types_in_comments: bool; 20 | 21 | ``` 22 | 23 | And `lib/parser_env.ml`: 24 | ``` 25 | 161a162 26 | + types_in_comments: bool; 27 | 170a172 28 | + types_in_comments = true; 29 | 229c231 30 | - let enable_types_in_comments = parse_options.types in 31 | --- 32 | + let enable_types_in_comments = parse_options.types && parse_options.types_in_comments in 33 | ``` 34 | 35 | Make sure it compiles and test passes: 36 | ```bash 37 | $ make test 38 | ... 39 | types_in_comments=false: OK 40 | types_in_comments=true: OK 41 | ``` 42 | 43 | To publish the package, run: 44 | ``` 45 | $ npm publish 46 | ``` 47 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/flow_parser_dot_js.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | let () = 9 | let exports = 10 | if (Js.typeof (Js.Unsafe.js_expr "exports") != Js.string "undefined") 11 | then Js.Unsafe.js_expr "exports" 12 | else begin 13 | let exports = Js.Unsafe.obj [||] in 14 | Js.Unsafe.set Js.Unsafe.global "flow" exports; 15 | exports 16 | end 17 | in 18 | let js_error_of_exn = function 19 | | Js.Error e -> 20 | Js.raise_js_error e 21 | | exn -> 22 | let msg = "Internal error: "^(Printexc.to_string exn) in 23 | Js.raise_js_error (Js.Unsafe.new_obj Js.error_constr [| 24 | Js.Unsafe.inject (Js.string msg) 25 | |]) 26 | in 27 | let parse content options = 28 | try Flow_parser_js.parse content options 29 | with exn -> js_error_of_exn exn 30 | in 31 | Js.Unsafe.set exports "parse" (Js.Unsafe.callback parse) 32 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/remove_assignify.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open InfraredAst 3 | 4 | exception Unexpected_compiler_phase of string 5 | 6 | let rec remove_assignify_statement (statement : statement) : statement = 7 | let (loc, statement) = statement in 8 | match statement with 9 | | Expression (expression_loc, Assignment (id, expr)) -> 10 | (* Give this statement the expression's location for now because I think when 11 | * it comes time to show the message, this location will be more accurate. *) 12 | (expression_loc, VariableDeclaration (id, expr)) 13 | | FunctionDeclaration (name, args, body) -> 14 | let body' = List.map remove_assignify_statement body in 15 | (loc, FunctionDeclaration (name, args, body')) 16 | | _ -> (loc, statement) 17 | 18 | let transform (program : program) : program = 19 | match program with 20 | | InfraredProgram (statements) -> 21 | let statements' = List.map (fun statement -> remove_assignify_statement statement) statements in 22 | InfraredProgram statements' 23 | | _ -> raise (Unexpected_compiler_phase "Expected InfraredProgram") 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nick Zuber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | pprintf = @printf "\n\033[36m<><>\033[39m \033[1m%s\033[0m \033[36m<><><><><><><><><><><><><><><><><><><><><><>\033[39m 🚀\n" "$(1)" 2 | p_update = @printf "\033[33m ↻\033[39m \033[89m%s\033[39m\n" "$(1)" 3 | p_add = @printf "\033[32m ↗\033[39m \033[89m%s\033[39m\n" "$(1)" 4 | p_remove = @printf "\033[31m ↘\033[39m \033[89m%s\033[39m\n" "$(1)" 5 | p_dot = @printf "\033[32m ∗\033[39m \033[89m%s\033[39m\n" "$(1)" 6 | p_dot_red = @printf "\033[31m ∗\033[39m \033[89m%s\033[39m\n" "$(1)" 7 | 8 | .PHONY: build test test-coverage clean 9 | 10 | build: 11 | $(call pprintf,Building project) 12 | dune build Infrared/main.exe 13 | cp _build/default/Infrared/main.exe bin/infrared.exe 14 | $(call p_dot,Done.) 15 | 16 | test: 17 | $(call pprintf,Running tests for project) 18 | make test-coverage 19 | $(call p_dot,Done.) 20 | 21 | test-coverage: 22 | $(call pprintf,Testing code coverage) 23 | sh test-coverage/Parser/run.sh 24 | 25 | test-coverage-verbose: 26 | $(call pprintf,Testing code coverage) 27 | sh test-coverage/Parser/run.sh --verbose 28 | 29 | clean: 30 | $(call pprintf,Cleaning project) 31 | dune clean 32 | $(call p_dot,Done.) 33 | -------------------------------------------------------------------------------- /InfraredParser/Parser.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | open InfraredUtils 3 | 4 | exception Infrared_parsing_error of int * string 5 | 6 | let infrared_program_of_flow_program (flow_program: program) : program = 7 | let alpha_pass = Alpha.StatementTransformer.transform flow_program in 8 | alpha_pass 9 | 10 | let flow_program_of_file ~(file : string) ~(source : string) : program = 11 | let flow_program = FlowParser.parse ~file ~source in 12 | flow_program 13 | 14 | let parse_source ~(file : string) ~(source : string) : program = 15 | try 16 | let flow_program = flow_program_of_file ~file ~source in 17 | let _ = if !Settings.debug_mode then 18 | begin 19 | (* This just prints the parsed FlowAST for reference while developing *) 20 | let _ = Printer.pprint_program_with_title "Flow Ast" flow_program in 21 | () 22 | end 23 | in 24 | infrared_program_of_flow_program flow_program 25 | with 26 | | FlowParser.Flow_parsing_error (count, message) -> 27 | raise (Infrared_parsing_error (count, message)) 28 | | Alpha.Unhandled_parsing_step (message) -> 29 | raise (Infrared_parsing_error (1, message)) 30 | -------------------------------------------------------------------------------- /tests/mock-react-project/file_0-1.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import {Remote} from './source' 4 | import * as Specifier from './source' 5 | import Default, {Remote} from './source' 6 | 7 | class MyComponent extends React.Component { 8 | static propTypes = { 9 | id, 10 | 'lit': 2, 11 | [2 + 2]: 4, 12 | children: PropTypes.node.isRequired 13 | }; 14 | 15 | some_literal = 42 16 | 17 | render () { 18 | return ( 19 |
20 |
22 | ); 23 | } 24 | } 25 | 26 | export function FunctionComponent (props) { 27 | const fnWillStillCauseRerender = () => {} 28 | return ( 29 | <> 30 |
31 | 32 | 33 | ); 34 | } 35 | 36 | const fnWillNotCauseRerender = () => {} 37 | 38 | function add (a, b) { return a + b + "str"; } 39 | 40 | var fn = function () {} 41 | 42 | function LocalFunctionComponent (props) { 43 | var a = 1; 44 | var b = 2; 45 | return ( 46 |
47 | ); 48 | } 49 | 50 | export default MyComponent; 51 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /InfraredParser/parsers/Flow/FlowParser.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | open FlowError 3 | 4 | exception Flow_parsing_error of int * string 5 | 6 | (** Does the work of parsing the raw file into components. *) 7 | let parse_source ~(file : string) ~(source : string) = 8 | let parse_options = Some Flow_parser.Parser_env.({ 9 | esproposal_optional_chaining = false; 10 | esproposal_class_instance_fields = true; 11 | esproposal_class_static_fields = true; 12 | esproposal_decorators = true; 13 | esproposal_export_star_as = true; 14 | types = true; 15 | types_in_comments = false; 16 | use_strict = false; 17 | }) 18 | in 19 | try 20 | Flow_parser.Parser_flow.program source ~parse_options 21 | with 22 | | Flow_parser.Parse_error.Error errs -> 23 | let message = FlowError.string_of_errors_in_file file errs in 24 | let count = List.length errs in 25 | raise (Flow_parsing_error (count, message)) 26 | 27 | (** Actually types the output to be a FlowProgram. *) 28 | let parse ~(file : string) ~(source : string) = 29 | let (ast, errs) = parse_source ~file ~source in 30 | let flow_program = FlowProgram (ast, errs) in 31 | flow_program 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Questions 2 | ---------- 3 | 4 | If you have any questions regarding the project, how something was implemented, or why something was done a certain way, feel free to ask! Please make sure to include `[QUESTION]` at the start of the title for this issue, as well as to label this issue as a "question". 5 | 6 | Reporting a Bug 7 | ---------------- 8 | 9 | If you've found a bug somewhere in the code or project, please make sure to include `[BUG]` at the start of the title for this issue, as well as to label this issue as a "bug". Make sure to write a concise and terse **description** of the bug, **where** you've found it, and any **suggestions** on fixing it (if applicable/you have any suggestions in mind). 10 | 11 | Suggesting a Feature 12 | --------------------- 13 | 14 | If you'd like to suggest a new feature or improvement to the project, please make sure to include `[ENHANCEMENT]` at the start of the title for this issue, as well as to label this issue as an "enhancement". Be sure to include a short write up on **why** this feature would be beneficial to implement into the project and any **suggestions** on how to go about implementing this feature (if applicable/you have any suggestions in mind). 15 | 16 | Thank you! 17 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/bin/.merlin: -------------------------------------------------------------------------------- 1 | B /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__gen-0.5.1-7d027135/lib/gen 2 | B /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__ocamlfind-1.8.0-348fa71d/lib/bytes 3 | B /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__sedlex-1.99.4-a0e003a2/lib/sedlex 4 | B /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__wtf8-1.0.1-29ae6569/lib/wtf8 5 | B ../_build/default/bin/.test_flow_parser.eobjs 6 | B ../_build/default/lib/.Flow_parser.objs 7 | S /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__gen-0.5.1-7d027135/lib/gen 8 | S /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__ocamlfind-1.8.0-348fa71d/lib/bytes 9 | S /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__sedlex-1.99.4-a0e003a2/lib/sedlex 10 | S /Users/zindel/.esy/3__________________________________________________________________/i/opam__slash__wtf8-1.0.1-29ae6569/lib/wtf8 11 | S . 12 | S ../lib 13 | FLG -w -40 14 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/README.md: -------------------------------------------------------------------------------- 1 | # The Flow Parser 2 | 3 | The Flow Parser is a JavaScript parser written in OCaml. It produces an AST that conforms to [SpiderMonkey's Parser API](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API) and that mostly matches what [esprima](http://esprima.org/) produces. The Flow Parser can be compiled to native code or can be compiled to JavaScript using [js_of_ocaml](http://ocsigen.org/js_of_ocaml/). 4 | 5 | ## Building the Flow Parser 6 | 7 | Building the Flow Parser requires OCaml. Compiling to JavaScript requires js_of_ocaml >= 2.8. 8 | 9 | ### Initial set up 10 | 11 | * [Install opam](https://opam.ocaml.org/doc/Install.html) 12 | * `opam install js_of_ocaml` 13 | 14 | ### Building the OCaml Flow Parser library 15 | 16 | make 17 | 18 | ### Compiling the Flow Parser to JavaScript 19 | 20 | make js 21 | 22 | ## Tests 23 | 24 | The Flow Parser's test suite tests the JavaScript version of the parser, so you will need js_of_ocaml installed. The tests and tools also have some node module dependencies, so you will need to run 25 | 26 | ### Initial set up 27 | 28 | * Follow the steps in [Building the Flow Parser](https://github.com/facebook/flow/blob/master/src/parser/README.md#building-the-flow-parser) 29 | * `npm install` 30 | 31 | ### Running the Tests 32 | 33 | make test 34 | -------------------------------------------------------------------------------- /InfraredUtils/Fs.ml: -------------------------------------------------------------------------------- 1 | let blacklist = 2 | [| ".git" 3 | ; "node_modules" 4 | ; "_build" 5 | |] 6 | 7 | let whitelist = 8 | [| ".js" 9 | ; ".jsx" 10 | |] 11 | 12 | let is_blacklisted path = 13 | Array.exists (fun blk -> Utils.is_substring blk path) blacklist 14 | 15 | let is_whitelisted file = 16 | Array.exists (fun wht -> wht = Filename.extension file) whitelist 17 | 18 | let is_directory_opt path : bool option = 19 | try Some (Sys.is_directory path) 20 | with Sys_error _ -> None 21 | 22 | let rec files_from_path (path : string) : string list = 23 | let is_dir_opt = is_directory_opt path in 24 | let is_invalid_file = is_blacklisted path in 25 | match (is_invalid_file, is_dir_opt) with 26 | | (true, _) -> [] 27 | | (false, None) -> [] 28 | | (false, Some true) -> 29 | let inner_paths : string array = Sys.readdir path in 30 | Array.fold_left 31 | (fun files inner_path -> 32 | let absolute_path = Filename.concat path inner_path in 33 | files @ (files_from_path absolute_path)) 34 | [] inner_paths 35 | | (false, Some false) -> 36 | let should_include = is_whitelisted path in 37 | if should_include then 38 | [path] 39 | else 40 | [] 41 | 42 | let read_file (file : string) : string = 43 | let ic = open_in file in 44 | let len = in_channel_length ic in 45 | let str = Bytes.create len in 46 | really_input ic str 0 len; 47 | close_in ic; 48 | Bytes.to_string str 49 | -------------------------------------------------------------------------------- /InfraredUtils/Utils.ml: -------------------------------------------------------------------------------- 1 | let is_substring (needle : string) (haystack : string) = 2 | let rgx_string = Printf.sprintf ".*\\(%s\\).*" needle in 3 | let rgx = Str.regexp rgx_string in 4 | Str.string_match rgx haystack 0 5 | 6 | let string_of_char_list cl = 7 | String.concat "" (List.map (String.make 1) cl) 8 | 9 | let char_list_of_string s = 10 | let rec exp i l = 11 | if i < 0 then l else exp (i - 1) (s.[i] :: l) in 12 | exp (String.length s - 1) [] 13 | 14 | let rand_lowercase_letter () : string = String.make 1 (Char.chr (97 + (Random.int 26))) 15 | let rand_uppercase_letter () : string = String.make 1 (Char.chr (65 + (Random.int 26))) 16 | let rand_number_as_string () : string = string_of_int (Random.int 10) 17 | let rand_char_as_string () : string = 18 | let seed = Random.int 3 in 19 | match seed with 20 | | 0 -> rand_lowercase_letter () 21 | | 1 -> rand_uppercase_letter () 22 | | _ -> rand_number_as_string () 23 | 24 | let generate_hash () : string = 25 | let size = 8 in 26 | let list_of_chars_as_strings = List.init size (fun _ -> rand_char_as_string ()) in 27 | String.concat "" list_of_chars_as_strings 28 | 29 | let math_min (a : int) (b : int) : int = 30 | if a < b then a else b 31 | 32 | let math_max (a : int) (b : int) : int = 33 | if a < b then b else a 34 | 35 | let parse_args_for_flags (args : string list) : (string list * string list) = 36 | List.partition (fun arg -> (String.sub arg 0 2) <> "--") args 37 | 38 | let is_flag_set (target : string) (flags : string list) : bool = 39 | List.exists (fun flag -> flag = ("--" ^ target)) flags 40 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/token_translator.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | 9 | module Translate (Impl : Translator_intf.S) : (sig 10 | type t 11 | val token: Parser_env.token_sink_result -> t 12 | val token_list: Parser_env.token_sink_result list -> t 13 | end with type t = Impl.t) = struct 14 | type t = Impl.t 15 | 16 | let token { Parser_env.token_loc; token; token_context } = 17 | let open Loc in 18 | 19 | Impl.obj [ 20 | ("type", Impl.string (Token.token_to_string token)); 21 | ("context", Impl.string Parser_env.Lex_mode.( 22 | match token_context with 23 | | NORMAL -> "normal" 24 | | TYPE -> "type" 25 | | JSX_TAG -> "jsxTag" 26 | | JSX_CHILD -> "jsxChild" 27 | | TEMPLATE -> "template" 28 | | REGEXP -> "regexp" 29 | )); 30 | ("loc", Impl.obj [ 31 | ("start", Impl.obj [ 32 | ("line", Impl.number (float token_loc.start.line)); 33 | ("column", Impl.number (float token_loc.start.column)); 34 | ]); 35 | ("end", Impl.obj [ 36 | ("line", Impl.number (float token_loc._end.line)); 37 | ("column", Impl.number (float token_loc._end.column)); 38 | ]); 39 | ]); 40 | ("range", Impl.array [ 41 | Impl.number (float token_loc.start.offset); 42 | Impl.number (float token_loc._end.offset); 43 | ]); 44 | ("value", Impl.string (Token.value_of_token token)); 45 | ] 46 | 47 | let token_list tokens = 48 | Impl.array (List.rev_map token tokens |> List.rev) 49 | 50 | end 51 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/initialize_function_declarations.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open InfraredAst 3 | 4 | exception Unexpected_compiler_phase of string 5 | 6 | let rec init_func_statement (statement : statement) (env : environment) : statement = 7 | let (loc, statement) = statement in 8 | match statement with 9 | | FunctionDeclaration ((name_loc, name), params, body) -> 10 | let param_d_types = List.map (fun (_, id) -> 11 | let generic = Generic id in 12 | (* Assign types to arguments *) 13 | Hashtbl.replace env id generic; 14 | generic 15 | ) params 16 | in 17 | let return_d_type = Unknown in 18 | (* Assign types to inner body function declarations *) 19 | let _ = List.map (fun statement -> init_func_statement statement env) body in 20 | let d_type = Primative (Function (param_d_types, return_d_type)) in 21 | Hashtbl.replace env name d_type; 22 | (loc, FunctionDeclaration ((name_loc, name), params, body)) 23 | | _ -> (loc, statement) 24 | 25 | (* The environment is just mutated here and it doesn't actually conver this into a 26 | * typed program. This is important because this phase happens before we begin to 27 | * typify the program. Function declarations are statements, so they don't actually 28 | * have a "type" like an expression would, but rather defines an identifier with a 29 | * type in the environment. *) 30 | let transform (env : environment) (program : program) : program = 31 | match program with 32 | | InfraredProgram (statements) -> 33 | let statements' = List.map (fun statement -> init_func_statement statement env) statements in 34 | InfraredProgram statements' 35 | | _ -> raise (Unexpected_compiler_phase "Expected InfraredProgram") 36 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/ast_utils.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | open Ast 9 | 10 | type binding = Loc.t * string 11 | 12 | let rec bindings_of_pattern = 13 | let open Pattern in 14 | let property acc = 15 | let open Object in 16 | function 17 | | Property (_, { Property.pattern = (_, p); _ }) 18 | | RestProperty (_, { RestProperty.argument = (_, p) }) -> 19 | bindings_of_pattern acc p 20 | in 21 | let element acc = 22 | let open Array in 23 | function 24 | | None -> acc 25 | | Some (Element (_, p)) 26 | | Some (RestElement (_, { RestElement.argument = (_, p) })) -> 27 | bindings_of_pattern acc p 28 | in 29 | fun acc -> 30 | function 31 | | Identifier { Identifier.name; _ } -> 32 | name::acc 33 | | Object { Object.properties; _ } -> 34 | List.fold_left property acc properties 35 | | Array { Array.elements; _ } -> 36 | List.fold_left element acc elements 37 | | Assignment { Assignment.left = (_, p); _ } -> 38 | bindings_of_pattern acc p 39 | | Expression _ -> 40 | failwith "expression pattern" 41 | 42 | let bindings_of_variable_declarations = 43 | let open Ast.Statement.VariableDeclaration in 44 | List.fold_left (fun acc -> function 45 | | _, { Declarator.id = (_, pattern); _ } -> 46 | bindings_of_pattern acc pattern 47 | ) [] 48 | 49 | let partition_directives statements = 50 | let open Ast.Statement in 51 | let rec helper directives = function 52 | | ((_, Expression { Expression.directive = Some _; _ }) as directive)::rest -> 53 | helper (directive::directives) rest 54 | | rest -> List.rev directives, rest 55 | in 56 | helper [] statements 57 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/pattern_cover.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | open Ast 9 | open Parser_common 10 | open Parser_env 11 | 12 | module type COVER = sig 13 | val as_expression : env -> pattern_cover -> Loc.t Expression.t 14 | val as_pattern : ?err:Parse_error.t -> env -> pattern_cover -> Loc.t Pattern.t 15 | val empty_errors : pattern_errors 16 | val rev_append_errors : pattern_errors -> pattern_errors -> pattern_errors 17 | val rev_errors : pattern_errors -> pattern_errors 18 | end 19 | 20 | module Cover 21 | (Parse: PARSER) 22 | : COVER = struct 23 | let as_expression env = function 24 | | Cover_expr expr -> expr 25 | | Cover_patt (expr, { if_expr; if_patt = _ }) -> 26 | List.iter (error_at env) if_expr; 27 | expr 28 | 29 | let as_pattern ?(err = Parse_error.InvalidLHSInAssignment) env cover = 30 | let expr = match cover with 31 | | Cover_expr expr -> expr 32 | | Cover_patt (expr, { if_expr = _; if_patt }) -> 33 | List.iter (error_at env) if_patt; 34 | expr 35 | in 36 | 37 | if not (Parse.is_assignable_lhs expr) 38 | then error_at env (fst expr, err); 39 | 40 | (match expr with 41 | | loc, Ast.Expression.Identifier (_, name) 42 | when is_restricted name -> 43 | strict_error_at env (loc, Error.StrictLHSAssignment) 44 | | _ -> ()); 45 | 46 | Parse.pattern_from_expr env expr 47 | 48 | let empty_errors = { if_patt = []; if_expr = [] } 49 | let rev_append_errors a b = 50 | { if_patt = List.rev_append a.if_patt b.if_patt; 51 | if_expr = List.rev_append a.if_expr b.if_expr; } 52 | let rev_errors a = 53 | { if_patt = List.rev a.if_patt; if_expr = List.rev a.if_expr } 54 | end 55 | -------------------------------------------------------------------------------- /Infrared/commands/help_command.ml: -------------------------------------------------------------------------------- 1 | let padding_size = 32 2 | 3 | let string_of_flags (flags : Flag.t list) : string = 4 | let strs = List.map (fun flag -> 5 | let open Flag in 6 | let spacing = String.make (padding_size - (String.length flag.name)) ' ' in 7 | Printf.sprintf "\n %s%s%s" 8 | flag.name 9 | spacing 10 | flag.doc 11 | ) flags 12 | in 13 | String.concat "" strs 14 | 15 | let get_help name_and_docs alias_and_docs = 16 | let title = "Usage: infrared [COMMAND]" in 17 | let cmds_title = "Valid values for [COMMAND]" in 18 | let aliases_title = "Valid aliases for [COMMAND]" in 19 | let cmds = List.fold_left 20 | (fun msg tuple -> 21 | let (name, doc, flags) = tuple in 22 | let flags_strs = string_of_flags flags in 23 | let spacing = String.make (padding_size - (String.length name)) ' ' in 24 | let cmsg = Printf.sprintf " %s%s%s%s" name spacing doc flags_strs in 25 | msg ^ "\n" ^ cmsg) 26 | "" 27 | name_and_docs 28 | in 29 | let aliases = List.fold_left 30 | (fun msg tuple -> 31 | let (alias, doc) = tuple in 32 | let spacing = String.make (padding_size - (String.length alias)) ' ' in 33 | let cmsg = Printf.sprintf " %s%s%s" alias spacing doc in 34 | msg ^ "\n" ^ cmsg) 35 | "" 36 | alias_and_docs 37 | in 38 | Printf.sprintf "%s\n\n%s%s\n\n%s%s\n" 39 | title 40 | cmds_title 41 | cmds 42 | aliases_title 43 | aliases 44 | 45 | 46 | let spec = Command.create 47 | ~name:"help" 48 | ~aliases:["-h"; "--help"] 49 | ~doc:"Print all of the possible usage information" 50 | ~flags:[] 51 | 52 | let exec = get_help 53 | 54 | type t = 55 | { spec: Command.t 56 | ; exec: (string * string * Flag.t list) list -> (string * string) list -> string 57 | } 58 | 59 | let command : t = 60 | { spec = spec 61 | ; exec = exec 62 | } 63 | -------------------------------------------------------------------------------- /InfraredUtils/Chalk.ml: -------------------------------------------------------------------------------- 1 | let bold str = Printf.sprintf "\x1b[1m%s\x1b[0m" str 2 | let underline str = Printf.sprintf "\x1b[4m%s\x1b[0m" str 3 | let invert str = Printf.sprintf "\x1b[7m%s\x1b[0m" str 4 | 5 | let black str = Printf.sprintf "\x1b[38;5;16m%s\x1b[39m" str 6 | let red str = Printf.sprintf "\x1b[31m%s\x1b[39m" str 7 | let green str = Printf.sprintf "\x1b[32m%s\x1b[39m" str 8 | let yellow str = Printf.sprintf "\x1b[33m%s\x1b[39m" str 9 | let blue str = Printf.sprintf "\x1b[34m%s\x1b[39m" str 10 | let magenta str = Printf.sprintf "\x1b[35m%s\x1b[39m" str 11 | let cyan str = Printf.sprintf "\x1b[36m%s\x1b[39m" str 12 | let gray str = Printf.sprintf "\x1b[90m%s\x1b[39m" str 13 | let white str = Printf.sprintf "\x1b[97m%s\x1b[39m" str 14 | 15 | let light_gray str = Printf.sprintf "\x1b[37m%s\x1b[39m" str 16 | let light_red str = Printf.sprintf "\x1b[91m%s\x1b[39m" str 17 | let light_green str = Printf.sprintf "\x1b[92m%s\x1b[39m" str 18 | let light_yellow str = Printf.sprintf "\x1b[93m%s\x1b[39m" str 19 | let light_blue str = Printf.sprintf "\x1b[94m%s\x1b[39m" str 20 | let light_magenta str = Printf.sprintf "\x1b[95m%s\x1b[39m" str 21 | let light_cyan str = Printf.sprintf "\x1b[96m%s\x1b[39m" str 22 | 23 | let bg_red str = Printf.sprintf "\x1b[41m%s\x1b[49m" str 24 | let bg_green str = Printf.sprintf "\x1b[42m%s\x1b[49m" str 25 | let bg_yellow str = Printf.sprintf "\x1b[43m%s\x1b[49m" str 26 | let bg_blue str = Printf.sprintf "\x1b[44m%s\x1b[49m" str 27 | let bg_magenta str = Printf.sprintf "\x1b[45m%s\x1b[49m" str 28 | let bg_cyan str = Printf.sprintf "\x1b[46m%s\x1b[49m" str 29 | let bg_gray str = Printf.sprintf "\x1b[100m%s\x1b[49m" str 30 | let bg_white str = Printf.sprintf "\x1b[107m%s\x1b[49m" str 31 | 32 | let bg_light_gray str = Printf.sprintf "\x1b[47m%s\x1b[49m" str 33 | let bg_light_red str = Printf.sprintf "\x1b[101m%s\x1b[49m" str 34 | let bg_light_green str = Printf.sprintf "\x1b[102m%s\x1b[49m" str 35 | let bg_light_yellow str = Printf.sprintf "\x1b[103m%s\x1b[49m" str 36 | let bg_light_blue str = Printf.sprintf "\x1b[104m%s\x1b[49m" str 37 | let bg_light_magenta str = Printf.sprintf "\x1b[105m%s\x1b[49m" str 38 | let bg_light_cyan str = Printf.sprintf "\x1b[106m%s\x1b[49m" str 39 | -------------------------------------------------------------------------------- /InfraredCompiler/Compiler.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open InfraredParser 3 | open InfraredUtils 4 | open TypePrinter 5 | 6 | let print_program (title : string) (program : program) : unit = 7 | Printf.printf "%s %s\n\n" 8 | (("[" ^ title ^ "]") |> Chalk.white |> Chalk.bold) 9 | (Printer.string_of_program program) 10 | 11 | let assign_types ~(file : string) ~(program : program) : program = 12 | let env : environment = Hashtbl.create 53 in 13 | let _ = file in 14 | let typed_program = 15 | program 16 | |> Remove_assignify.transform 17 | |> Uniquify.transform 18 | |> Initialize_function_declarations.transform env 19 | |> Typify.transform env 20 | |> Function_returns_refinement.transform env 21 | |> Realign_typed_expressions.transform env 22 | in 23 | typed_program 24 | 25 | (* inner_function_refinement - function args get refined based on use within function *) 26 | (* global_refinement - global refinement for all vars and usages *) 27 | 28 | let assign_types_with_debugging ~(file : string) ~(program : program) : program = 29 | let env : environment = Hashtbl.create 53 in 30 | Printf.printf "%s\n%s\n" 31 | (Printer.string_of_title "Original program") 32 | (Fs.read_file file); 33 | let typed_program = 34 | program |> Printer.pprint_program_with_title "Converted program" 35 | |> Remove_assignify.transform |> Printer.pprint_program_with_title "Transform assignments into declarations" 36 | |> Uniquify.transform |> Printer.pprint_program_with_title "Uniqufy variable names (removes shadowing)" 37 | |> (Initialize_function_declarations.transform env) |> Printer.pprint_program_with_title "Initialize function declarations within closures" 38 | |> (Typify.transform env) |> Printer.pprint_program_with_title "Assign base types" 39 | |> (Function_returns_refinement.transform env) |> Printer.pprint_program_with_title "Assign Functions their return types" 40 | |> (Realign_typed_expressions.transform env) |> Printer.pprint_program_with_title "Re-align typed expressions" 41 | in 42 | typed_program 43 | 44 | let assign_types ~(file : string) ~(program : program) = 45 | let typed_program = if !Settings.debug_mode then 46 | assign_types_with_debugging ~file ~program 47 | else 48 | assign_types ~file ~program 49 | in 50 | if !Settings.show_types_in_console then 51 | TypePrinter.pp_types_within_file file typed_program; 52 | typed_program 53 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/file_key.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | type t = 9 | | LibFile of string 10 | | SourceFile of string 11 | | JsonFile of string 12 | (* A resource that might get required, like .css, .jpg, etc. We don't parse 13 | these, just check that they exist *) 14 | | ResourceFile of string 15 | | Builtins 16 | 17 | let to_string = function 18 | | LibFile x | SourceFile x | JsonFile x | ResourceFile x -> x 19 | | Builtins -> "(global)" 20 | 21 | let to_path = function 22 | | LibFile x | SourceFile x | JsonFile x | ResourceFile x -> Ok x 23 | | Builtins -> Error "File key refers to a builtin" 24 | 25 | let compare = 26 | (* builtins, then libs, then source and json files at the same priority since 27 | JSON files are basically source files. We don't actually read resource 28 | files so they come last *) 29 | let order_of_filename = function 30 | | Builtins -> 1 31 | | LibFile _ -> 2 32 | | SourceFile _ -> 3 33 | | JsonFile _ -> 3 34 | | ResourceFile _ -> 4 35 | in 36 | fun a b -> 37 | let k = (order_of_filename a) - (order_of_filename b) in 38 | if k <> 0 then k 39 | else String.compare (to_string a) (to_string b) 40 | 41 | let compare_opt a b = 42 | match a, b with 43 | | Some _, None -> -1 44 | | None, Some _ -> 1 45 | | None, None -> 0 46 | | Some a, Some b -> compare a b 47 | 48 | let is_lib_file = function 49 | | LibFile _ -> true 50 | | Builtins -> true 51 | | SourceFile _ -> false 52 | | JsonFile _ -> false 53 | | ResourceFile _ -> false 54 | 55 | let map f = function 56 | | LibFile filename -> LibFile (f filename) 57 | | SourceFile filename -> SourceFile (f filename) 58 | | JsonFile filename -> JsonFile (f filename) 59 | | ResourceFile filename -> ResourceFile (f filename) 60 | | Builtins -> Builtins 61 | 62 | let exists f = function 63 | | LibFile filename 64 | | SourceFile filename 65 | | JsonFile filename 66 | | ResourceFile filename -> f filename 67 | | Builtins -> false 68 | 69 | let check_suffix filename suffix = 70 | exists (fun fn -> Filename.check_suffix fn suffix) filename 71 | 72 | let chop_suffix filename suffix = 73 | map (fun fn -> Filename.chop_suffix fn suffix) filename 74 | 75 | let with_suffix filename suffix = 76 | map (fun fn -> fn ^ suffix) filename 77 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/lex_env.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | 9 | type t = { 10 | lex_source : File_key.t option; 11 | lex_lb : Sedlexing.lexbuf; 12 | lex_bol : bol; 13 | lex_in_comment_syntax : bool; 14 | lex_enable_comment_syntax: bool; 15 | lex_state : lex_state; 16 | } 17 | 18 | (* bol = Beginning Of Line *) 19 | and bol = { 20 | line: int; 21 | offset: int; 22 | } 23 | 24 | and lex_state = { 25 | lex_errors_acc: (Loc.t * Parse_error.t) list; 26 | lex_comments_acc: Loc.t Ast.Comment.t list; 27 | } 28 | 29 | let empty_lex_state = { 30 | lex_errors_acc = []; 31 | lex_comments_acc = []; 32 | } 33 | 34 | let new_lex_env lex_source lex_lb ~enable_types_in_comments = { 35 | lex_source; 36 | lex_lb; 37 | lex_bol = { line = 1; offset = 0}; 38 | lex_in_comment_syntax = false; 39 | lex_enable_comment_syntax = enable_types_in_comments; 40 | lex_state = empty_lex_state; 41 | } 42 | 43 | let get_and_clear_state env = 44 | let state = env.lex_state in 45 | let env = if state != empty_lex_state 46 | then { env with lex_state = empty_lex_state } 47 | else env 48 | in 49 | env, state 50 | 51 | let lexbuf env = env.lex_lb 52 | let with_lexbuf ~lexbuf env = { env with lex_lb = lexbuf } 53 | let source env = env.lex_source 54 | let state env = env.lex_state 55 | let line env = env.lex_bol.line 56 | let bol_offset env = env.lex_bol.offset 57 | let is_in_comment_syntax env = env.lex_in_comment_syntax 58 | let is_comment_syntax_enabled env = env.lex_enable_comment_syntax 59 | let in_comment_syntax is_in env = 60 | if is_in <> env.lex_in_comment_syntax 61 | then { env with lex_in_comment_syntax = is_in } 62 | else env 63 | 64 | (* TODO *) 65 | let debug_string_of_lexbuf _lb = "" 66 | 67 | let debug_string_of_lex_env (env: t) = 68 | let source = match (source env) with 69 | | None -> "None" 70 | | Some x -> Printf.sprintf "Some %S" (File_key.to_string x) 71 | in 72 | Printf.sprintf 73 | "{\n \ 74 | lex_source = %s\n \ 75 | lex_lb = %s\n \ 76 | lex_in_comment_syntax = %b\n \ 77 | lex_enable_comment_syntax = %b\n \ 78 | lex_state = {errors = (count = %d); comments = (count = %d)}\n\ 79 | }" 80 | source 81 | (debug_string_of_lexbuf env.lex_lb) 82 | (is_in_comment_syntax env) 83 | (is_comment_syntax_enabled env) 84 | (List.length (state env).lex_errors_acc) 85 | (List.length (state env).lex_comments_acc) 86 | -------------------------------------------------------------------------------- /tests/mock-project/dir1/file_1-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Queue 3 | * {front} Node, the first element in the queue 4 | * {back} Node, the last element in the queue 5 | * {size} number, the number of nodes in the queue 6 | * 7 | * Asymptotic time complexities 8 | * +-------------------+ 9 | * | enqueue | O(1) | 10 | * | dequeue | O(1) | 11 | * +-------------------+ 12 | * 13 | */ 14 | 15 | const Node = require("../Nodes/unidirectional_node.js"); 16 | 17 | /** 18 | * Single argument constructor. 19 | * @param {*} [data] data for front node of queue 20 | * @return {void} 21 | */ 22 | const Queue = function (data) { 23 | this.front = 0; 24 | this.back; 25 | this.size; 26 | if (typeof data !== "undefined") { 27 | this.front = new Node(data); 28 | this.back = this.front; 29 | this.front.next = this.back; 30 | this.back.next = null; 31 | this.size = 1; 32 | } else { 33 | this.front = null; 34 | this.back = null; 35 | this.size = 0; 36 | } 37 | }; 38 | 39 | /** 40 | * Creates a node with the given data and adds that node 41 | * to the back of the queue 42 | * @param {*} data for head node of linked list 43 | * @return {void} 44 | */ 45 | Queue.prototype.enqueue = function (data) { 46 | if (typeof data === "undefined") { 47 | throw new Error("Too few arguments in Queue.enqueue"); 48 | } 49 | 50 | this[function () {}]; 51 | 52 | var newNode = new Node(data); 53 | // Check to see if front/back exist 54 | if (this.front === null && this.back === null) { 55 | this.front = newNode; 56 | continue; 57 | this.back = this.front; 58 | this.front.next = this.back; 59 | this.back.next = null; 60 | ++this.size; 61 | } else if (this.front !== null && this.back !== null) { 62 | // Add to end of the queue 63 | this.back.next = newNode; 64 | this.back = newNode; 65 | ++this.size; 66 | } 67 | // Both front and back should either be set or null; if not then something went wrong somewhere 68 | else { 69 | throw new Error( 70 | "Either front or back is not set in an a queue at once. Please report this to https://github.com/nickzuber/needle/issues" 71 | ); 72 | } 73 | }; 74 | 75 | /** 76 | * Removes the node at the front of the queue 77 | * @param {void} 78 | * @return {void} 79 | */ 80 | Queue.prototype.dequeue = function () { 81 | if (this.size === 0) { 82 | throw new Error("Attempted to dequeue from empty queue in Queue.enqueue"); 83 | } 84 | // Remove from the front 85 | var newHead = this.front.next; 86 | this.front = newHead; 87 | --this.size; 88 | }; 89 | 90 | module.exports = Queue; 91 | 92 | function f(x) { 93 | var arr = [x]; 94 | } 95 | -------------------------------------------------------------------------------- /test-coverage/Parser/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rgxFindFn="and (string_of_statement|string_of_expression) " 4 | rgxFindUnfinishedMatchStmt=":space:+| ([a-zA-Z]+) _ ->" 5 | rgxFindFinishedMatchStmt=":space:+| ([a-zA-Z]+)" 6 | rgxIsValidBlock="^[A-Z]" 7 | 8 | flag=$1 9 | begin=0 10 | suites=0 11 | suites_failed=0 12 | pass=0 13 | fail=0 14 | fail_local=0 15 | 16 | filePrinter="./InfraredParser/Printer.ml" 17 | 18 | print_if_verbose () { 19 | if [[ "$flag" = "--verbose" || "$flag" = "-v" ]]; then 20 | echo $1 21 | fi 22 | } 23 | 24 | fn_printer_covereage () { 25 | while read -r line 26 | do 27 | # You were testing a suite and it had just finished. 28 | if [[ begin -eq 1 && -z $line ]]; then 29 | if [[ fail_local -gt 0 ]]; then 30 | ((suites_failed++)) 31 | fi 32 | begin=0 33 | # You have found a new test suite. 34 | elif [[ $line =~ $rgxFindFn ]]; then 35 | print_if_verbose "" 36 | echo "\033[42;38;5;16;1m TEST \033[49;39;0m \033[32;2mInfraredParser/Printer.ml#\033[39;0m\033[1m${BASH_REMATCH[1]}\033[0m" 37 | begin=1 38 | pass_local=0 39 | fail_local=0 40 | ((suites++)) 41 | # You have found an incomplete method within the test suite. 42 | elif [[ begin -eq 1 && $line =~ $rgxFindUnfinishedMatchStmt ]]; then 43 | local name=${BASH_REMATCH[1]} 44 | if [[ -n $name ]]; then 45 | print_if_verbose " \033[90m↺ $name\033[39;0m" 46 | ((fail++)) 47 | ((fail_local++)) 48 | fi 49 | # You have found a complete method within the test suite. 50 | elif [[ begin -eq 1 && $line =~ $rgxFindFinishedMatchStmt ]]; then 51 | local name=${BASH_REMATCH[1]} 52 | if [[ -n $name && $name =~ $rgxIsValidBlock ]]; then 53 | print_if_verbose " \033[32;1m✓\033[39;0m $name" 54 | ((pass++)) 55 | fi 56 | fi 57 | local name="" 58 | done < "$filePrinter" 59 | } 60 | 61 | # Run all the functions for coverage. 62 | fn_printer_covereage 63 | 64 | # Print the final coverage report. 65 | total=$((pass+fail)) 66 | percentage=$((100*$pass/$total)) 67 | percentage_exact=$(echo "$pass/$total*100" | bc -l) 68 | echo "" 69 | if [[ suites_failed -gt 0 ]]; then 70 | echo "\033[97;1mTest suites:\033[39m\033[38;38;5;1m $suites_failed failed\033[0;0m, $suites total" 71 | else 72 | echo "\033[97;1mTest suites:\033[39m\033[32;1m $((suites-suites_failed)) passed\033[0;0m, $suites total" 73 | fi 74 | echo "\033[97;1mTests: \033[39m\033[32;1m $pass passed\033[0;0m, $total total" 75 | echo "\033[97;1mCoverage: \033[0m $percentage% \033[39m\033[32;1m▁▂▃\033[0m" 76 | echo "\033[90mRan all covereage functions matching \033[0m/$rgxFindFn/i" 77 | echo "\033[32minfrared-coverage-reporter >> Report generaged (@TODO) \033[0;0m" 78 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/libflowparser.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | (* do NOT change the order of these constructors! the C code relies on ocaml's 9 | memory representation, which is order dependent. *) 10 | type json = 11 | | JObject of (string * json) list 12 | | JArray of json list 13 | | JString of string 14 | | JNumber of float 15 | | JBool of bool 16 | | JNull 17 | 18 | module AbstractTranslator : ( 19 | Translator_intf.S with type t = json 20 | ) = struct 21 | type t = json 22 | let string x = JString x 23 | let bool x = JBool x 24 | let obj props = JObject props 25 | let array arr = JArray arr 26 | let number x = JNumber x 27 | let null = JNull 28 | let regexp _loc _pattern _flags = JNull 29 | end 30 | 31 | module Translate = Estree_translator.Translate (AbstractTranslator) (struct 32 | (* TODO: make these configurable via CLI flags *) 33 | let include_comments = true 34 | let include_locs = true 35 | end) 36 | 37 | module Token_translator = Token_translator.Translate (AbstractTranslator) 38 | 39 | let translate_tokens tokens = 40 | AbstractTranslator.array (List.rev_map Token_translator.token tokens) 41 | 42 | let convert_options opts = 43 | let open Parser_env in 44 | List.fold_left (fun (opts, tokens) (k, v) -> 45 | match k with 46 | | "esproposal_class_instance_fields" -> 47 | { opts with esproposal_class_instance_fields = v }, tokens 48 | | "esproposal_class_static_fields" -> 49 | { opts with esproposal_class_static_fields = v }, tokens 50 | | "esproposal_decorators" -> 51 | { opts with esproposal_decorators = v }, tokens 52 | | "esproposal_export_star_as" -> 53 | { opts with esproposal_export_star_as = v }, tokens 54 | | "esproposal_optional_chaining" -> 55 | { opts with esproposal_optional_chaining = v }, tokens 56 | | "types" -> 57 | { opts with types = v }, tokens 58 | | "use_strict" -> 59 | { opts with use_strict = v }, tokens 60 | | "tokens" -> 61 | opts, v 62 | | _ -> 63 | opts, tokens (* ignore unknown stuff for future-compatibility *) 64 | ) (Parser_env.default_parse_options, false) opts 65 | 66 | let parse content options = 67 | let parse_options, include_tokens = convert_options options in 68 | 69 | let rev_tokens = ref [] in 70 | let token_sink = 71 | if include_tokens then Some (fun token_data -> rev_tokens := token_data::!rev_tokens) 72 | else None 73 | in 74 | 75 | let (ast, errors) = Parser_flow.program 76 | ~fail:false ~parse_options:(Some parse_options) ~token_sink 77 | content 78 | in 79 | 80 | match Translate.program ast with 81 | | JObject params -> 82 | let params = ("errors", Translate.errors errors)::params in 83 | let params = 84 | if include_tokens then ("tokens", translate_tokens !rev_tokens)::params 85 | else params 86 | in 87 | JObject params 88 | | _ -> assert false 89 | 90 | (* TODO: register/handle Parse_error.Error *) 91 | let () = Callback.register "flow_parse" parse 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infrared 2 | 3 | > Blazing fast, light-weight, inferred static type checker for JavaScript. 4 | 5 | Infrared is an configurable & efficient static type checker for JavaScript. This is done by statically inferring a [fluid type system](#what-is-a-fluid-type-system) onto your entire program – tracking the types of your variables as they change – and raising type errors before they happen at runtime. 6 | 7 | ## What is a Fluid Type System? 8 | 9 | A fluid type system is no foreign idea – its a forgiving set of typing rules that _change_ as your program changes. This means no variables are ever committed to a single type – if that variable changes its type somewhere in the program, Infrared keeps track of it. 10 | 11 | JavaScript is a dynamic language, and Infrared doesn't want to change that. While other type systems out there want you to change the way you program (and change your JavaScript into something else), Infrared does the opposite. 12 | 13 | To understand the way Infrared fits into the typing ecosystem, consider the following: 14 | 15 | - If you're looking for a superset type system that tries to promote soundness, you should use [Flow](https://flow.org/). 16 | - If you're looking for a superset type system that encourages unsoundness, you should use [TypeScript](https://www.typescriptlang.org/). 17 | - If you don't want to change anything in your project, but still want to know the types of things in your program + have some type safety at compile time, you should use Infrared. 18 | 19 | ## Planning, Roadmap, and What Lies Ahead 20 | 21 | Infrared is a really big project, so naturally it's a pretty good idea to make sure we plan things out carefully to avoid a janky-mess. 22 | 23 | I'm using Figma to organize the different sections and responsibilities of each part of Infrared (parser, compiler, server, etc.). Feel free to follow along and check out [what I have mapped out so far](https://www.figma.com/file/VLacrQPUdTH19kJSiGy5zCzu/workflow?node-id=0%3A1). 24 | 25 | Unfortunately, Figma only reflects the finalized parts of the development _roadmap_. This means there's a lot of cool work – like typing rules, reduction strategies, discrete proofs, etc – that aren't in this document. 26 | 27 | Since those bits are written in a physical notebook, it's hard for me to share publically online. The good news is that I plan on writing a white paper once this project is finished, and all of the cool stuff will be included in there. 28 | 29 | Until then, I'm more than happy to chat with anybody who's interested to learn more – feel free to reach out on [Twitter](https://twitter.com/nick_zuber/). 30 | 31 | ## FAQ 32 | 33 | **Q** – Can I use this? 34 | 35 | **A** – Not yet. This project is still under development, but expect an alpha release soon(_ish_)! 36 | 37 | ## License 38 | 39 | This software is free to use under the MIT License. See [this reference](https://opensource.org/licenses/MIT) for license text and copyright information. 40 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/function_returns_refinement.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open TypedInfraredAst 3 | 4 | exception Unexpected_compiler_phase of string 5 | exception Unexpected_function_data_type of string 6 | 7 | let get_type tbl key = 8 | try Hashtbl.find tbl key 9 | with _ -> Generic "unable-to-find-this-type-this-is-a-bug" 10 | 11 | let rec flatten_statement (statement : statement) : statement list = 12 | let (loc, statement) = statement in 13 | match statement with 14 | | Block statements -> flatten_statements statements 15 | | If (_, s1, s2) -> List.append (flatten_statement s1) (flatten_statement s2) 16 | | _ -> [(loc, statement)] 17 | 18 | and flatten_statements (statements : statement list) : statement list = 19 | let flat_statements = List.map flatten_statement statements in 20 | List.flatten flat_statements 21 | 22 | let get_all_return_d_types (statements : statement list) : data_type list = 23 | let statements' = flatten_statements statements in 24 | List.filter_map (fun statement -> 25 | let (_, statement) = statement in 26 | match statement with 27 | | Return (d_type, _) -> Some d_type 28 | | _ -> None 29 | ) statements' 30 | 31 | let get_param_d_types (d_type : data_type) : data_type list = 32 | match d_type with 33 | | Primative (Function (param_d_types, _)) -> param_d_types 34 | | _ -> 35 | raise 36 | (Unexpected_function_data_type "A function was found with a non-function data type") 37 | 38 | let rec function_returns_refine_statement (statement : statement) (env : environment) : statement = 39 | let (loc, statement) = statement in 40 | match statement with 41 | | FunctionDeclaration ((name_loc, name), params, body) -> 42 | let prev_d_type = get_type env name in 43 | let param_d_types = get_param_d_types prev_d_type in 44 | let return_d_type = get_return_type_of_function body in 45 | let d_type = Primative (Function (param_d_types, return_d_type)) in 46 | Hashtbl.replace env name d_type; 47 | let body' = List.map (fun s -> function_returns_refine_statement s env) body in 48 | (loc, FunctionDeclaration ((name_loc, name), params, body')) 49 | | _ -> (loc, statement) 50 | 51 | and get_return_type_of_function (statements : statement list) : data_type = 52 | let return_statement_d_types = get_all_return_d_types statements in 53 | match List.length return_statement_d_types with 54 | | 0 -> Primative Undefined 55 | | 1 -> List.hd return_statement_d_types 56 | | _ -> Union return_statement_d_types 57 | 58 | (* The environment is just mutated here and it doesn't actually conver this into a 59 | * typed program. This is important because this phase happens before we begin to 60 | * typify the program. Function declarations are statements, so they don't actually 61 | * have a "type" like an expression would, but rather defines an identifier with a 62 | * type in the environment. *) 63 | let transform (env : environment) (program : program) : program = 64 | match program with 65 | | TypedInfraredProgram (statements, _env) -> 66 | let statements' = List.map 67 | (fun statement -> function_returns_refine_statement statement env) 68 | statements 69 | in 70 | TypedInfraredProgram (statements', env) 71 | | _ -> raise (Unexpected_compiler_phase "Expected TypedInfraredProgram") 72 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/typify.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open InfraredAst 3 | 4 | exception Unexpected_compiler_phase of string 5 | 6 | let get_type tbl key = 7 | try Hashtbl.find tbl key 8 | with _ -> Primative Undefined 9 | 10 | let get_type_of_argument tbl key = 11 | try Hashtbl.find tbl key 12 | with _ -> Generic key 13 | 14 | let rec typify_statement (statement : statement) (env : environment) : TypedInfraredAst.statement = 15 | let (loc, statement) = statement in 16 | match statement with 17 | | VariableDeclaration ((id_loc, id), expression) -> 18 | let d_type = type_of_expression expression env in 19 | let typed_expression = (d_type, expression) in 20 | Hashtbl.replace env id d_type; 21 | (loc, VariableDeclaration ((id_loc, id), typed_expression)) 22 | | FunctionDeclaration ((name_loc, name), params, body) -> 23 | let typed_body = List.map (fun s -> typify_statement s env) body in 24 | (loc, FunctionDeclaration ((name_loc, name), params, typed_body)) 25 | | Return expr -> 26 | let d_type = type_of_expression expr env in 27 | let typed_expression = (d_type, expr) in 28 | (loc, Return typed_expression) 29 | | Expression expr -> 30 | let d_type = type_of_expression expr env in 31 | let typed_expression = (d_type, expr) in 32 | (loc, Expression typed_expression) 33 | | Block statements -> 34 | let statements' = List.map (fun s -> typify_statement s env) statements in 35 | (loc, Block statements') 36 | | If (expr, s1, s2) -> 37 | let d_type = type_of_expression expr env in 38 | let typed_expression = (d_type, expr) in 39 | let s1' = typify_statement s1 env in 40 | let s2' = typify_statement s2 env in 41 | (loc, If (typed_expression, s1', s2')) 42 | 43 | and type_of_expression (expression : expression) (env : environment) : data_type = 44 | let (_, expression) = expression in 45 | match expression with 46 | | String _ -> Primative String 47 | | Number _ -> Primative Number 48 | | Boolean _ -> Primative Boolean 49 | | Null -> Primative Null 50 | | Undefined -> Primative Undefined 51 | | Variable (_, id) -> get_type env id 52 | | BinaryOperation (_op, left, right) -> 53 | let d_type_left = type_of_expression left env in 54 | let d_type_right = type_of_expression right env in 55 | Reduction [d_type_left; d_type_right] 56 | | Object pairs -> 57 | let typed_pairs = List.map (fun pair -> 58 | let ((_, key), value) = pair in 59 | let d_type = type_of_expression value env in 60 | (key, d_type) 61 | ) pairs in 62 | Primative (Object typed_pairs) 63 | | Access (e1, e2) -> 64 | let inner_d_type = type_of_expression e1 env in 65 | Drill (inner_d_type, e2) 66 | | Call (callee, args) -> 67 | let callee_d_type = type_of_expression callee env in 68 | let args_d_types = List.map (fun arg -> type_of_expression arg env) args in 69 | Exec (callee_d_type, args_d_types) 70 | | _ -> Generic "typify-todo-expression" 71 | 72 | let transform (env : environment) (program : program) : program = 73 | match program with 74 | | InfraredProgram (statements) -> 75 | let statements' = List.map (fun statement -> typify_statement statement env) statements in 76 | TypedInfraredProgram (statements', env) 77 | | _ -> raise (Unexpected_compiler_phase "Expected InfraredProgram") 78 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at zuber.nicholas@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /InfraredParser/parsers/Flow/FlowError.ml: -------------------------------------------------------------------------------- 1 | open InfraredUtils 2 | 3 | module FlowError = struct 4 | let split = Str.split (Str.regexp "\n") 5 | let pad (n : int) = match n with 6 | | _ when n < 10 -> " " 7 | | _ when n < 100 -> " " 8 | | _ -> "" 9 | let s (n : int) = match n with 10 | | _ when n < 10 -> " " 11 | | _ when n < 100 -> " " 12 | | _ when n < 1000 -> " " 13 | | _ -> "" 14 | 15 | let interleave_error_within_file ~padding file err : string = 16 | let open Flow_parser.Loc in 17 | let padding = String.make padding ' ' in 18 | (* The amount of lines we show above and below the error lines. *) 19 | let preview_length = 0 in 20 | let (loc, err) = err in 21 | let error_string = Flow_parser.Parse_error.PP.error err in 22 | let source = Fs.read_file file in 23 | (* Lines of file to print *) 24 | let lines = split source in 25 | let line_start = max (loc.start.line - preview_length) 1 in 26 | let line_end = loc._end.line + preview_length in 27 | let preview_string = ref "" in 28 | let _ = List.iteri (fun i line -> 29 | let i = i + 1 in 30 | match i with 31 | | _ when i = loc.start.line -> 32 | let spacing = String.make (loc.start.column + 1) ' ' in 33 | let underline = String.make (loc._end.column - loc.start.column) '^' in 34 | let line_string = Printf.sprintf "%s%s\n%s%s" 35 | padding 36 | line 37 | (Chalk.gray ((s i) ^ (pad i) ^ padding ^ " ")) 38 | (spacing ^ padding ^ (underline |> Chalk.red |> Chalk.bold)) 39 | in 40 | let str = Printf.sprintf "%s%s %s%s| %s" 41 | padding 42 | (">" |> Chalk.bold |> Chalk.red) 43 | (string_of_int i) 44 | (pad i) 45 | line_string 46 | in 47 | preview_string := !preview_string ^ "\n" ^ str 48 | | _ when i > line_end -> () 49 | | _ when i >= line_start -> 50 | let line_string = line in 51 | let str = 52 | Printf.sprintf "%s %s%s| %s" 53 | padding 54 | (string_of_int i) 55 | (pad i) 56 | line_string 57 | in 58 | preview_string := !preview_string ^ "\n" ^ (Chalk.gray str) 59 | | _ -> () 60 | ) lines 61 | in 62 | Printf.sprintf "\n%s%s %s%s.%s" 63 | padding 64 | (Chalk.bold "Error") 65 | (Chalk.white "(parsing): ") 66 | (Chalk.white error_string) 67 | !preview_string 68 | 69 | let string_of_errors_in_file file errs : string = 70 | let errors_string = 71 | errs 72 | |> List.map (fun err -> interleave_error_within_file ~padding:8 file err) 73 | |> String.concat ("") 74 | in 75 | errors_string ^ "\n" 76 | 77 | let string_of_error err : string = 78 | let (loc, err) = err in 79 | let location_string = Flow_parser.Loc.to_string loc in 80 | let error_string = Flow_parser.Parse_error.PP.error err in 81 | Printf.sprintf "%s: %s" 82 | location_string 83 | error_string 84 | 85 | let string_of_errors errs : string = 86 | let prefix = " - " in 87 | let errors_string = 88 | errs 89 | |> List.map (fun err -> string_of_error err) 90 | |> String.concat ("\n" ^ prefix) 91 | in 92 | prefix ^ errors_string ^ "\n" 93 | end 94 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/libflowparser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #define CAML_NAME_SPACE 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace flowparser { 17 | 18 | typedef std::map options_t; 19 | 20 | static value list_head(value props) { 21 | return Field(props, 0); 22 | } 23 | 24 | static bool list_has_next(value props) { 25 | return props != Val_emptylist; 26 | } 27 | 28 | static value list_tail(value props) { 29 | return Field(props, 1); 30 | } 31 | 32 | static char* get_prop_key(value prop) { 33 | return String_val(Field(prop, 0)); 34 | } 35 | 36 | static value get_prop_value(value prop) { 37 | return Field(prop, 1); 38 | } 39 | 40 | value cons(value hd, value tl) { 41 | CAMLparam2(hd, tl); 42 | CAMLlocal1(ret); 43 | ret = caml_alloc(2, 0); 44 | Store_field(ret, 0, hd); 45 | Store_field(ret, 1, tl); 46 | CAMLreturn(ret); 47 | } 48 | 49 | template 50 | class AbstractTranslator { 51 | public: 52 | virtual T convert_string(char *str) = 0; 53 | virtual T convert_number(double n) = 0; 54 | virtual T convert_bool(long b) = 0; 55 | virtual T convert_null() = 0; 56 | virtual T convert_undefined() = 0; 57 | virtual T convert_object(value props) = 0; 58 | virtual T convert_array(value items) = 0; 59 | 60 | T convert_json(value v) { 61 | if (Is_long(v)) { 62 | if (Long_val(v) == 0) { 63 | return convert_null(); 64 | } 65 | // no other immediate values should exist 66 | return convert_undefined(); // TODO: raise v8 exception 67 | }; 68 | switch (Tag_val(v)) { 69 | // JObject 70 | case 0: 71 | return convert_object(Field(v, 0)); 72 | 73 | // JArray 74 | case 1: 75 | return convert_array(Field(v, 0)); 76 | 77 | // JString 78 | case 2: 79 | return convert_string(String_val(Field(v, 0))); 80 | 81 | // JNumber 82 | case 3: 83 | return convert_number(Double_val(Field(v, 0))); 84 | 85 | // JBool 86 | case 4: 87 | return convert_bool(Long_val(Field(v, 0))); 88 | 89 | default: 90 | // no other tags exist! 91 | return convert_undefined(); // TODO: raise v8 exception 92 | } 93 | } 94 | 95 | T parse(const char *content, options_t opts) { 96 | CAMLparam0(); 97 | CAMLlocal4(content_val, option_val, options_val, result_val); 98 | 99 | static value * func = caml_named_value("flow_parse"); 100 | 101 | content_val = caml_copy_string(content); 102 | 103 | options_val = Val_int(0); // empty list 104 | for (auto& x : opts) { 105 | option_val = caml_alloc_tuple(2); 106 | Store_field(option_val, 0, caml_copy_string(x.first.c_str())); 107 | Store_field(option_val, 1, Val_bool(x.second)); 108 | options_val = cons(option_val, options_val); 109 | } 110 | 111 | result_val = caml_callback2(*func, content_val, options_val); 112 | 113 | CAMLreturnT(T, convert_object(Field(result_val, 0))); 114 | } 115 | }; 116 | 117 | void init() { 118 | char *argv[] = {NULL}; 119 | caml_startup(argv); 120 | } 121 | 122 | } // namespace flow 123 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/realign_typed_expressions.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser.Ast 2 | open TypedInfraredAst 3 | 4 | exception Unexpected_compiler_phase of string 5 | 6 | let get_type tbl key = 7 | try Hashtbl.find tbl key 8 | with _ -> Primative Undefined 9 | 10 | let get_type_of_argument tbl key = 11 | try Hashtbl.find tbl key 12 | with _ -> Generic key 13 | 14 | let rec realign_typed_statement (statement : statement) (env : environment) : TypedInfraredAst.statement = 15 | let (loc, statement) = statement in 16 | match statement with 17 | | VariableDeclaration ((id_loc, id), t_expr) -> 18 | let (_, expr) = t_expr in 19 | let d_type = type_of_expression expr env in 20 | let typed_expression = (d_type, expr) in 21 | Hashtbl.replace env id d_type; 22 | (loc, VariableDeclaration ((id_loc, id), typed_expression)) 23 | | FunctionDeclaration ((name_loc, name), params, body) -> 24 | let typed_body = List.map (fun s -> realign_typed_statement s env) body in 25 | (loc, FunctionDeclaration ((name_loc, name), params, typed_body)) 26 | | Return t_expr -> 27 | let (_, expr) = t_expr in 28 | let d_type = type_of_expression expr env in 29 | let typed_expression = (d_type, expr) in 30 | (loc, Return typed_expression) 31 | | Expression t_expr -> 32 | let (_, expr) = t_expr in 33 | let d_type = type_of_expression expr env in 34 | let typed_expression = (d_type, expr) in 35 | (loc, Expression typed_expression) 36 | | Block statements -> 37 | let statements' = List.map (fun s -> realign_typed_statement s env) statements in 38 | (loc, Block statements') 39 | | If (t_expr, s1, s2) -> 40 | let (_, expr) = t_expr in 41 | let d_type = type_of_expression expr env in 42 | let typed_expression = (d_type, expr) in 43 | let s1' = realign_typed_statement s1 env in 44 | let s2' = realign_typed_statement s2 env in 45 | (loc, If (typed_expression, s1', s2')) 46 | 47 | and type_of_expression (expression : InfraredAst.expression) (env : environment) : data_type = 48 | let (_, expression) = expression in 49 | match expression with 50 | | String _ -> Primative String 51 | | Number _ -> Primative Number 52 | | Boolean _ -> Primative Boolean 53 | | Null -> Primative Null 54 | | Undefined -> Primative Undefined 55 | | Variable (_, id) -> get_type env id 56 | | BinaryOperation (_op, left, right) -> 57 | let d_type_left = type_of_expression left env in 58 | let d_type_right = type_of_expression right env in 59 | Reduction [d_type_left; d_type_right] 60 | | Object pairs -> 61 | let typed_pairs = List.map (fun pair -> 62 | let ((_, key), value) = pair in 63 | let d_type = type_of_expression value env in 64 | (key, d_type) 65 | ) pairs in 66 | Primative (Object typed_pairs) 67 | | Access (e1, e2) -> 68 | let inner_d_type = type_of_expression e1 env in 69 | Drill (inner_d_type, e2) 70 | | Call (callee, args) -> 71 | let callee_d_type = type_of_expression callee env in 72 | let args_d_types = List.map (fun arg -> type_of_expression arg env) args in 73 | Exec (callee_d_type, args_d_types) 74 | | _ -> Generic "typify-todo-expression" 75 | 76 | let transform (env : environment) (program : program) : program = 77 | match program with 78 | | TypedInfraredProgram (statements, _env) -> 79 | let statements' = List.map (fun statement -> realign_typed_statement statement env) statements in 80 | TypedInfraredProgram (statements', env) 81 | | _ -> raise (Unexpected_compiler_phase "Expected TypedInfraredProgram") 82 | -------------------------------------------------------------------------------- /Infrared/commands/parse_command.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser 2 | open InfraredUtils 3 | open Ast 4 | 5 | type parser_result = 6 | | Success of string * program 7 | | Fail of string * int * string (* file, Infrared_parsing_error *) 8 | | Nil of string 9 | 10 | let parse_file (file : string) : parser_result = 11 | let open InfraredParser.Parser in 12 | let source = Fs.read_file file in 13 | try 14 | let prog = Parser.parse_source ~file ~source in 15 | Success (file, prog) 16 | with 17 | | Infrared_parsing_error (count, message) -> 18 | Fail (file, count, message) 19 | | _ -> 20 | Nil file 21 | 22 | let print_result_summary start_time files err_files err_count : unit = 23 | let end_time = Unix.gettimeofday () in 24 | Printf.printf "\n%sChecked %s files in %ss" 25 | (Chalk.green " ↗ ") 26 | (files 27 | |> List.length 28 | |> string_of_int 29 | |> Chalk.green) 30 | (String.sub (string_of_float (end_time -. start_time)) 0 4); 31 | if err_files > 0 || err_count > 0 then 32 | Printf.printf "\n%sFailed to parse %s files with %s errors" 33 | (Chalk.red " ↘ ") 34 | (err_files 35 | |> string_of_int 36 | |> Chalk.red) 37 | (err_count 38 | |> string_of_int 39 | |> Chalk.red); 40 | Printf.printf "\n\n" 41 | 42 | let string_of_parser_result (res : parser_result) : string = 43 | let open Chalk in 44 | match res with 45 | | Success (file, prog) -> 46 | Printf.sprintf "%s %s%s\n" 47 | (" Pass " |> green |> bold) 48 | (gray file) 49 | ("\n" ^ Printer.string_of_program prog) 50 | | Fail (file, _count, message) -> 51 | let failure = Printf.sprintf "%s %s\n" 52 | (" Fail " |> red |> bold) 53 | (gray file) 54 | in 55 | Printf.sprintf "%s%s\n" failure message 56 | | Nil file -> 57 | Printf.sprintf "%s %s\n" 58 | (" Fatal " |> red |> bold) 59 | (gray file) 60 | 61 | let check_files (files : string list) : unit = 62 | let start_time = Unix.gettimeofday () in 63 | let results = List.map (fun file -> parse_file file) files in 64 | let result_strings = List.map string_of_parser_result results in 65 | let () = List.iter (fun str -> Printf.printf "%s" str) result_strings in 66 | let (err_files, err_count) = List.fold_left (fun acc res -> 67 | match res with 68 | | Fail (_file, count, _message) -> 69 | let (acc_f, acc_c) = acc in 70 | (acc_f + 1, acc_c + count) 71 | | Nil _file -> 72 | let (acc_f, acc_c) = acc in 73 | (acc_f + 1, acc_c) 74 | | _ -> acc) 75 | (0, 0) results 76 | in 77 | print_result_summary start_time files err_files err_count 78 | 79 | let parse_files args : unit = 80 | print_endline ""; 81 | match args with 82 | | [] -> () 83 | | arg :: [] -> 84 | let paths = 85 | arg 86 | |> Fs.files_from_path 87 | |> List.rev 88 | in 89 | check_files paths 90 | | args -> 91 | let paths = 92 | args 93 | |> List.map Fs.files_from_path 94 | |> List.flatten 95 | |> List.rev 96 | in 97 | check_files paths 98 | 99 | let spec = Command.create 100 | ~name:"parse" 101 | ~aliases:["pp"] 102 | ~doc:"Parse and print the given JavaScript files" 103 | ~flags:[] 104 | 105 | let exec = parse_files 106 | 107 | type t = 108 | { spec: Command.t 109 | ; exec: string list -> unit 110 | } 111 | 112 | let command : t = 113 | { spec = spec 114 | ; exec = exec 115 | } 116 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/loc.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | type position = { 9 | line: int; 10 | column: int; 11 | offset: int; 12 | } 13 | 14 | type t = { 15 | source: File_key.t option; 16 | start: position; 17 | _end: position; 18 | } 19 | 20 | let none = { 21 | source = None; 22 | start = { line = 0; column = 0; offset = 0; }; 23 | _end = { line = 0; column = 0; offset = 0; }; 24 | } 25 | 26 | let btwn loc1 loc2 = { 27 | source = loc1.source; 28 | start = loc1.start; 29 | _end = loc2._end; 30 | } 31 | 32 | let btwn_exclusive loc1 loc2 = { 33 | source = loc1.source; 34 | start = loc1._end; 35 | _end = loc2.start; 36 | } 37 | 38 | (* Returns the position immediately before the start of the given loc. If the 39 | given loc is at the beginning of a line, return the position of the first 40 | char on the same line. *) 41 | let char_before loc = 42 | let start = 43 | let { line; column; offset } = loc.start in 44 | let column, offset = if column > 0 45 | then column - 1, offset - 1 46 | else column, offset in 47 | { line; column; offset } 48 | in 49 | let _end = loc.start in 50 | { loc with start; _end } 51 | 52 | (* Returns the location of the first character in the given loc. Not accurate if the 53 | * first line is a newline character, but is still consistent with loc orderings. *) 54 | let first_char loc = 55 | let start = loc.start in 56 | let _end = {start with column = start.column + 1; offset = start.offset + 1} in 57 | {loc with _end} 58 | 59 | let pos_cmp a b = 60 | let k = a.line - b.line in if k = 0 then a.column - b.column else k 61 | 62 | (** 63 | * If `a` spans (completely contains) `b`, then returns 0. 64 | * If `b` starts before `a` (even if it ends inside), returns < 0. 65 | * If `b` ends after `a` (even if it starts inside), returns > 0. 66 | *) 67 | let span_compare a b = 68 | let k = File_key.compare_opt a.source b.source in 69 | if k = 0 then 70 | let k = pos_cmp a.start b.start in 71 | if k <= 0 then 72 | let k = pos_cmp a._end b._end in 73 | if k >= 0 then 0 else -1 74 | else 1 75 | else k 76 | 77 | (* Returns true if loc1 entirely overlaps loc2 *) 78 | let contains loc1 loc2 = span_compare loc1 loc2 = 0 79 | 80 | (* Returns true if loc1 intersects loc2 at all *) 81 | let lines_intersect loc1 loc2 = 82 | File_key.compare_opt loc1.source loc2.source = 0 && not ( 83 | (loc1._end.line < loc2.start.line) || 84 | (loc1.start.line > loc2._end.line) 85 | ) 86 | 87 | let compare loc1 loc2 = 88 | let k = File_key.compare_opt loc1.source loc2.source in 89 | if k = 0 then 90 | let k = pos_cmp loc1.start loc2.start in 91 | if k = 0 then pos_cmp loc1._end loc2._end 92 | else k 93 | else k 94 | 95 | let equal loc1 loc2 = compare loc1 loc2 = 0 96 | 97 | (** 98 | * This is mostly useful for debugging purposes. 99 | * Please don't dead-code delete this! 100 | *) 101 | let to_string ?(include_source=false) loc = 102 | let source = 103 | if include_source 104 | then Printf.sprintf "%S: " ( 105 | match loc.source with 106 | | Some src -> File_key.to_string src 107 | | None -> "" 108 | ) else "" 109 | in 110 | let pos = Printf.sprintf "(%d, %d) to (%d, %d)" 111 | loc.start.line 112 | loc.start.column 113 | loc._end.line 114 | loc._end.column 115 | in 116 | source ^ pos 117 | 118 | let source loc = loc.source 119 | 120 | let make file line col = 121 | { 122 | source = Some file; 123 | start = { line; column = col; offset = 0; }; 124 | _end = { line; column = col + 1; offset = 0; }; 125 | } 126 | -------------------------------------------------------------------------------- /InfraredParser/parsers/ast.ml: -------------------------------------------------------------------------------- 1 | module Loc = Flow_parser.Loc 2 | 3 | module rec InfraredAst : sig 4 | type identifier' = string 5 | 6 | and unop = 7 | | Negate 8 | | Not 9 | 10 | and binop = 11 | | Plus 12 | | Minus 13 | | Multiply 14 | | Divide 15 | | Exponent 16 | | Modulo 17 | | LeftShift 18 | | RightShift 19 | | BitOr 20 | | BitXor 21 | | BitAnd 22 | | And 23 | | Or 24 | | In 25 | | InstanceOf 26 | | Compare of cmp 27 | 28 | and cmp = 29 | | Equal 30 | | NotEqual 31 | | GreaterThan 32 | | LessThan 33 | 34 | and property = 35 | | PropertyExpression of expression 36 | | PropertyIdentifier of identifier 37 | 38 | and expression' = 39 | | Variable of identifier 40 | | String of string 41 | | Number of int 42 | | Boolean of bool 43 | | Object of (identifier * expression) list 44 | | Null 45 | | Undefined 46 | | Call of expression * (expression list) (* e(e1, e2) *) 47 | | Access of expression * property (* e.e *) 48 | | Assignment of identifier * expression (* x = e *) 49 | | UnaryOperation of unop * expression 50 | | BinaryOperation of binop * expression * expression 51 | 52 | and statement' = 53 | (* Recall that VariableAssignment don't exist for our AST. 54 | * Any VariableAssignments will be considered as new variable 55 | * declarations, so we can track any type branches for free. *) 56 | | VariableDeclaration of identifier * expression (* var x = e *) 57 | | FunctionDeclaration of identifier * (identifier list) * (statement list) (* name, arguments, body *) 58 | | If of expression * statement * statement 59 | | Return of expression 60 | | Expression of expression 61 | | Block of statement list 62 | 63 | and expression = Loc.t * expression' 64 | and statement = Loc.t * statement' 65 | and identifier = Loc.t * identifier' 66 | end = InfraredAst 67 | 68 | type primative_data_type = 69 | | Null 70 | | Undefined 71 | | String 72 | | Boolean 73 | | Number 74 | | Object of (string * data_type) list (* PropertyName, Value *) 75 | | Array of data_type 76 | | Function of data_type list * data_type (* Arguments, ReturnType *) 77 | 78 | and data_type = 79 | | Primative of primative_data_type 80 | | Generic of string (* tag *) 81 | | Defer of InfraredAst.identifier (* Do we need this? Might be resolved via Exec *) 82 | | Drill of data_type * InfraredAst.property 83 | | Exec of data_type * (data_type list) (* f(a, b, c) *) 84 | | Reduction of data_type list (* operations on expressions *) 85 | | Union of data_type list 86 | | Unknown 87 | 88 | type environment = (string, data_type) Hashtbl.t 89 | 90 | (* Same as InfraredAst, only this has a typed expression *) 91 | module rec TypedInfraredAst : sig 92 | type typed_expression = data_type * InfraredAst.expression 93 | 94 | and statement' = 95 | (* Recall that VariableAssignment don't exist for our AST. 96 | * Any VariableAssignments will be considered as new variable 97 | * declarations, so we can track any type branches for free. *) 98 | | VariableDeclaration of InfraredAst.identifier * typed_expression (* var x = e *) 99 | | FunctionDeclaration of InfraredAst.identifier * (InfraredAst.identifier list) * (statement list) (* name, arguments, body *) 100 | | If of typed_expression * statement * statement 101 | | Return of typed_expression 102 | | Expression of typed_expression 103 | | Block of statement list 104 | 105 | and statement = Loc.t * statement' 106 | end = TypedInfraredAst 107 | 108 | type program = 109 | | FlowProgram of Flow_parser.Loc.t Flow_parser.Ast.program * 110 | (Flow_parser.Loc.t * Flow_parser.Parser_common.Error.t) list 111 | | InfraredProgram of InfraredAst.statement list 112 | | TypedInfraredProgram of TypedInfraredAst.statement list * environment 113 | -------------------------------------------------------------------------------- /Infrared/cli.ml: -------------------------------------------------------------------------------- 1 | open InfraredUtils 2 | 3 | type valid_command = 4 | | Help of Help_command.t 5 | | Version of Version_command.t 6 | | Check of Check_command.t 7 | | Parse of Parse_command.t 8 | 9 | type any_command = 10 | | Valid of valid_command 11 | | Invalid of string 12 | 13 | let version_command = Version Version_command.command 14 | let help_command = Help Help_command.command 15 | let check_command = Check Check_command.command 16 | let parse_command = Parse Parse_command.command 17 | 18 | let any_command_of_string name : any_command = 19 | match name with 20 | | "-v" 21 | | "--version" 22 | | "version" -> Valid version_command 23 | | "-h" 24 | | "--help" 25 | | "help" -> Valid help_command 26 | | "ch" 27 | | "check" -> Valid check_command 28 | | "pp" 29 | | "parse" -> Valid parse_command 30 | | _ -> Invalid name 31 | 32 | let doc_of_valid_command vc : string = 33 | match vc with 34 | | Help h -> h.spec.doc 35 | | Version v -> v.spec.doc 36 | | Check c -> c.spec.doc 37 | | Parse p -> p.spec.doc 38 | 39 | let flags_of_valid_command vc : Flag.t list = 40 | match vc with 41 | | Help h -> h.spec.flags 42 | | Version v -> v.spec.flags 43 | | Check c -> c.spec.flags 44 | | Parse p -> p.spec.flags 45 | 46 | let name_of_valid_command vc : string = 47 | match vc with 48 | | Help h -> h.spec.name 49 | | Version v -> v.spec.name 50 | | Check c -> c.spec.name 51 | | Parse p -> p.spec.name 52 | 53 | let aliases_of_valid_command vc : string list = 54 | match vc with 55 | | Help h -> h.spec.aliases 56 | | Version v -> v.spec.aliases 57 | | Check c -> c.spec.aliases 58 | | Parse p -> p.spec.aliases 59 | 60 | module InfraredShell : sig 61 | val commands : valid_command list 62 | val report_command_error : string -> unit 63 | val exec : unit -> unit 64 | end = struct 65 | let commands = [ 66 | version_command; 67 | help_command; 68 | check_command; 69 | parse_command; 70 | ] 71 | 72 | let report_command_error msg = 73 | Printf.printf "Error: %s\nFor a list of valid commands try `infrared help`\n\n" msg 74 | 75 | let greeting () = 76 | Printf.printf "%s%s%s\n\n" 77 | "Running \x1b[1minfrared\x1b[0m v" 78 | (Version_command.exec ()) 79 | " — Inferred static type checker for JavaScript." 80 | 81 | let exec () = 82 | let argv = Array.to_list Sys.argv in 83 | match argv with 84 | | [] -> report_command_error "" 85 | | _prgm :: [] -> greeting () 86 | | _prgm :: cmd :: args -> 87 | let command = any_command_of_string cmd in 88 | match command with 89 | | Valid vcmd -> begin 90 | let (args, flags) = Utils.parse_args_for_flags args in 91 | match vcmd with 92 | | Check c -> c.exec ~flags:flags args 93 | | Parse p -> p.exec args 94 | | Version v -> Printf.printf "v%s\n\n" (v.exec ()) 95 | | Help h -> 96 | let name_and_docs : (string * string * Flag.t list) list = 97 | List.fold_left 98 | (fun tuples command -> 99 | ( name_of_valid_command command 100 | , doc_of_valid_command command 101 | , flags_of_valid_command command 102 | ) :: tuples) 103 | [] 104 | commands 105 | in 106 | let alias_and_docs : (string * string) list = 107 | List.fold_left 108 | (fun tuples command -> 109 | let command_name = name_of_valid_command command in 110 | let aliases = aliases_of_valid_command command in 111 | let alias_strs = String.concat ", " aliases in 112 | let alias_and_docs = (alias_strs, "Alias for " ^ command_name) in 113 | [alias_and_docs] @ tuples) 114 | [] 115 | commands 116 | in 117 | Printf.printf "%s\n" (h.exec name_and_docs alias_and_docs) 118 | end 119 | | Invalid name -> 120 | report_command_error 121 | (Printf.sprintf "Unknown command \"%s\"" name) 122 | end 123 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/flow_parser_js.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | module JsTranslator : sig 9 | val translation_errors: (Loc.t * Parse_error.t) list ref 10 | include Translator_intf.S 11 | end = struct 12 | type t = Js.Unsafe.any 13 | 14 | let translation_errors = ref [] 15 | 16 | let string x = Js.Unsafe.inject (Js.string x) 17 | let bool x = Js.Unsafe.inject (Js.bool x) 18 | let obj props = Js.Unsafe.inject (Js.Unsafe.obj (Array.of_list props)) 19 | let array arr = Js.Unsafe.inject (Js.array (Array.of_list arr)) 20 | let number x = Js.Unsafe.inject (Js.number_of_float x) 21 | let null = Js.Unsafe.inject Js.null 22 | let regexp loc pattern flags = 23 | let regexp = try 24 | Js.Unsafe.new_obj (Js.Unsafe.variable "RegExp") [| 25 | string pattern; 26 | string flags; 27 | |] 28 | with _ -> 29 | translation_errors := (loc, Parse_error.InvalidRegExp)::!translation_errors; 30 | (* Invalid RegExp. We already validated the flags, but we've been 31 | * too lazy to write a JS regexp parser in Ocaml, so we didn't know 32 | * the pattern was invalid. We'll recover with an empty pattern. 33 | *) 34 | Js.Unsafe.new_obj (Js.Unsafe.variable "RegExp") [| 35 | string ""; 36 | string flags; 37 | |] 38 | in 39 | Js.Unsafe.inject regexp 40 | end 41 | 42 | module Translate = Estree_translator.Translate (JsTranslator) (struct 43 | let include_comments = true 44 | let include_locs = true 45 | end) 46 | 47 | module Token_translator = Token_translator.Translate (JsTranslator) 48 | 49 | let parse_options jsopts = Parser_env.( 50 | let opts = default_parse_options in 51 | 52 | let decorators = Js.Unsafe.get jsopts "esproposal_decorators" in 53 | let opts = if Js.Optdef.test decorators 54 | then { opts with esproposal_decorators = Js.to_bool decorators; } 55 | else opts in 56 | 57 | let class_instance_fields = Js.Unsafe.get jsopts "esproposal_class_instance_fields" in 58 | let opts = if Js.Optdef.test class_instance_fields 59 | then { opts with esproposal_class_instance_fields = Js.to_bool class_instance_fields; } 60 | else opts in 61 | 62 | let class_static_fields = Js.Unsafe.get jsopts "esproposal_class_static_fields" in 63 | let opts = if Js.Optdef.test class_static_fields 64 | then { opts with esproposal_class_static_fields = Js.to_bool class_static_fields; } 65 | else opts in 66 | 67 | let export_star_as = Js.Unsafe.get jsopts "esproposal_export_star_as" in 68 | let opts = if Js.Optdef.test export_star_as 69 | then { opts with esproposal_export_star_as = Js.to_bool export_star_as; } 70 | else opts in 71 | 72 | let optional_chaining = Js.Unsafe.get jsopts "esproposal_optional_chaining" in 73 | let opts = if Js.Optdef.test optional_chaining 74 | then { opts with esproposal_optional_chaining = Js.to_bool optional_chaining; } 75 | else opts in 76 | 77 | let types = Js.Unsafe.get jsopts "types" in 78 | let opts = if Js.Optdef.test types 79 | then { opts with types = Js.to_bool types; } 80 | else opts in 81 | 82 | opts 83 | ) 84 | 85 | let translate_tokens tokens = 86 | JsTranslator.array (List.rev_map Token_translator.token tokens) 87 | 88 | let parse content options = 89 | let options = 90 | if options = Js.undefined 91 | then Js.Unsafe.obj [||] 92 | else options 93 | in 94 | let content = Js.to_string content in 95 | let parse_options = Some (parse_options options) in 96 | 97 | let include_tokens = 98 | let tokens = Js.Unsafe.get options "tokens" in 99 | Js.Optdef.test tokens && Js.to_bool tokens 100 | in 101 | let rev_tokens = ref [] in 102 | let token_sink = 103 | if include_tokens then 104 | Some (fun token_data -> 105 | rev_tokens := token_data::!rev_tokens 106 | ) 107 | else None 108 | in 109 | 110 | let (ocaml_ast, errors) = Parser_flow.program ~fail:false ~parse_options ~token_sink content in 111 | JsTranslator.translation_errors := []; 112 | let ret = Translate.program ocaml_ast in 113 | let translation_errors = !JsTranslator.translation_errors in 114 | Js.Unsafe.set ret "errors" (Translate.errors (errors @ translation_errors)); 115 | if include_tokens then Js.Unsafe.set ret "tokens" (translate_tokens !rev_tokens); 116 | ret 117 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-present, Facebook, Inc. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | DIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 7 | TOP=$(DIR)/../.. 8 | REL_DIR=src/parser 9 | 10 | OCB = ocamlbuild -use-ocamlfind 11 | 12 | NATIVE_OBJECT_FILES=\ 13 | hack/utils/sys/files.o\ 14 | hack/utils/sys/getrusage.o\ 15 | hack/utils/sys/nproc.o\ 16 | hack/utils/sys/realpath.o\ 17 | hack/utils/sys/sysinfo.o\ 18 | hack/utils/sys/processor_info.o\ 19 | hack/utils/sys/priorities.o 20 | 21 | RUNNER_DEPS=\ 22 | hack/heap\ 23 | hack/injection/default_injector\ 24 | hack/utils\ 25 | hack/utils/collections\ 26 | hack/utils/disk\ 27 | hack/utils/hh_json\ 28 | hack/utils/sys\ 29 | hack/third-party/core\ 30 | src/common/utils\ 31 | src/parser\ 32 | src/parser_utils 33 | 34 | OCAML_PATH=$(shell ocamlc -where) 35 | OCAML_HEADERS=\ 36 | $(sort $(patsubst $(OCAML_PATH)/%,dist/libflowparser/include/%, \ 37 | $(filter $(OCAML_PATH)/%,$(shell \ 38 | $(CC) -I $(OCAML_PATH) -MM -MT deps libflowparser.h \ 39 | )))) 40 | 41 | all: build-parser 42 | 43 | clean: 44 | $(OCB) -clean; \ 45 | cd $(TOP); \ 46 | $(OCB) -clean; \ 47 | rm -f $(REL_DIR)/flow_parser.js; \ 48 | rm -rf $(REL_DIR)/dist 49 | 50 | build-parser: 51 | cd $(TOP); \ 52 | $(OCB) -no-links $(REL_DIR)/parser_flow.cmxa 53 | 54 | .PHONY: libflowparser.native.o 55 | libflowparser.native.o: 56 | cd $(TOP) && $(OCB) -no-links -tag "runtime_variant(_pic)" \ 57 | $(REL_DIR)/libflowparser.native.o 58 | 59 | dist/libflowparser/lib/libflowparser.a: libflowparser.native.o 60 | @mkdir -p "$(@D)" 61 | if [ ! -e "$@" -o "$(OCAML_PATH)/libasmrun_pic.a" -nt "$@" -o "$(TOP)/_build/$(REL_DIR)/libflowparser.native.o" -nt "$@" ]; then \ 62 | echo "Rebuilding $@"; \ 63 | cp "$(OCAML_PATH)/libasmrun_pic.a" "$@"; \ 64 | ar rcs "$@" "$(TOP)/_build/$(REL_DIR)/libflowparser.native.o"; \ 65 | else \ 66 | echo "Not rebuilding $@, already up to date"; \ 67 | fi 68 | test -e "$@" || exit 1 69 | 70 | $(OCAML_HEADERS): dist/libflowparser/include/%: $(OCAML_PATH)/% 71 | @mkdir -p "$(@D)" 72 | cp "$<" "$@" 73 | 74 | dist/libflowparser/include/flowparser/libflowparser.h: libflowparser.h 75 | @mkdir -p "$(@D)" 76 | cp "$<" "$@" 77 | 78 | dist/libflowparser.zip: \ 79 | $(OCAML_HEADERS) \ 80 | dist/libflowparser/include/flowparser/libflowparser.h \ 81 | dist/libflowparser/lib/libflowparser.a 82 | cd dist && zip -r $(@F) libflowparser 83 | 84 | js: 85 | cd $(TOP); \ 86 | $(OCB) -no-links -pkgs js_of_ocaml $(REL_DIR)/flow_parser_dot_js.byte; \ 87 | [ -e "$(REL_DIR)/flow_parser.js" -a "$(REL_DIR)/flow_parser.js" -nt "_build/$(REL_DIR)/flow_parser_dot_js.byte" ] || \ 88 | js_of_ocaml --opt 3 \ 89 | -o $(REL_DIR)/flow_parser.js \ 90 | _build/$(REL_DIR)/flow_parser_dot_js.byte 91 | 92 | test-js: js 93 | cd $(TOP)/packages/flow-parser; npm test 94 | 95 | ../../_build/$(REL_DIR)/test/run_esprima_tests.native: build-parser 96 | cd $(TOP); \ 97 | $(OCB) \ 98 | -ocamlc "ocamlopt" \ 99 | $(NATIVE_OBJECT_FILES); \ 100 | $(OCB) \ 101 | $(foreach dir,$(RUNNER_DEPS),-I $(dir)) \ 102 | -lib unix -lib str \ 103 | -lflags "$(NATIVE_OBJECT_FILES)" \ 104 | $(REL_DIR)/test/run_esprima_tests.native; \ 105 | rm run_esprima_tests.native 106 | 107 | ../../_build/$(REL_DIR)/test/run_hardcoded_tests.native: build-parser 108 | cd $(TOP); \ 109 | $(OCB) \ 110 | -ocamlc "ocamlopt -ccopt -DNO_SQLITE3" \ 111 | $(NATIVE_OBJECT_FILES); \ 112 | $(OCB) \ 113 | $(foreach dir,$(RUNNER_DEPS),-I $(dir)) \ 114 | -lib unix -lib str \ 115 | -lflags "$(NATIVE_OBJECT_FILES)" \ 116 | -tag debug \ 117 | $(REL_DIR)/test/run_hardcoded_tests.native; \ 118 | rm run_hardcoded_tests.native 119 | 120 | test-esprima-ocaml: ../../_build/$(REL_DIR)/test/run_esprima_tests.native 121 | cd $(TOP); \ 122 | _build/$(REL_DIR)/test/run_esprima_tests.native $(REL_DIR)/test/esprima/ 123 | 124 | test-hardcoded-ocaml: ../../_build/$(REL_DIR)/test/run_esprima_tests.native 125 | cd $(TOP); \ 126 | _build/$(REL_DIR)/test/run_esprima_tests.native $(REL_DIR)/test/flow/ 127 | 128 | test-ocaml: test-esprima-ocaml test-hardcoded-ocaml 129 | 130 | test: test-js test-ocaml 131 | 132 | ocamlfind-install: 133 | cd $(TOP); \ 134 | $(OCB) $(REL_DIR)/parser_flow.cma $(REL_DIR)/parser_flow.cmxa; \ 135 | ocamlfind install flow_parser $(REL_DIR)/META \ 136 | _build/$(REL_DIR)/parser_flow.a \ 137 | _build/$(REL_DIR)/parser_flow.cma \ 138 | _build/$(REL_DIR)/parser_flow.cmxa \ 139 | _build/$(REL_DIR)/*.cmi 140 | 141 | lexer.native: lexer.ml 142 | $(OCB) $@ 143 | -------------------------------------------------------------------------------- /InfraredParser/TypePrinter.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | open InfraredUtils 3 | open Flow_parser 4 | 5 | type type_data = Loc.t * data_type 6 | type type_mapping = (int, type_data) Hashtbl.t 7 | 8 | let get_type tbl key : data_type = 9 | try Hashtbl.find tbl key 10 | with _ -> Unknown 11 | 12 | let get_type_data tbl key : type_data option = 13 | try Some (Hashtbl.find tbl key) 14 | with _ -> None 15 | 16 | let rec walk_expression (expression : TypedInfraredAst.typed_expression) (env : environment) (type_map : type_mapping) : unit = 17 | let open InfraredAst in 18 | let open Flow_parser.Loc in 19 | let (expression_type, (expression_loc, expression)) = expression in 20 | match expression with 21 | | Variable (id_loc, id) -> 22 | let line_number = id_loc.start.line in 23 | let d_type = get_type env id in 24 | Hashtbl.replace type_map line_number (id_loc, d_type); 25 | () 26 | | BinaryOperation _ -> 27 | let line_number = expression_loc.start.line in 28 | Hashtbl.replace type_map line_number (expression_loc, expression_type); 29 | | _ -> () 30 | 31 | and walk_statement (statement : TypedInfraredAst.statement) (env : environment) (type_map : type_mapping) : unit = 32 | let open TypedInfraredAst in 33 | let open Flow_parser.Loc in 34 | let (statement_loc, statement) = statement in 35 | match statement with 36 | | VariableDeclaration ((id_loc, id), _) -> 37 | let line_number = id_loc.start.line in 38 | let d_type = get_type env id in 39 | Hashtbl.replace type_map line_number (id_loc, d_type); 40 | () 41 | | FunctionDeclaration ((name_loc, name), _args, body) -> 42 | let line_number = name_loc.start.line in 43 | let d_type = get_type env name in 44 | Hashtbl.replace type_map line_number (name_loc, d_type); 45 | List.iter (fun statement -> walk_statement statement env type_map) body 46 | | If (_expr, s1, s2) -> 47 | walk_statement s1 env type_map; 48 | walk_statement s2 env type_map 49 | | Expression expr -> walk_expression expr env type_map 50 | | Return (d_type, _expr) -> 51 | let line_number = statement_loc.start.line in 52 | Hashtbl.replace type_map line_number (statement_loc, d_type); 53 | | Block body -> List.iter (fun statement -> walk_statement statement env type_map) body 54 | 55 | module TypePrinter = struct 56 | let split = Str.split (Str.regexp "\n") 57 | 58 | let pad (n : int) = match n with 59 | | _ when n < 10 -> " " 60 | | _ when n < 100 -> " " 61 | | _ -> "" 62 | 63 | let pad_of_number (n : int) = match n with 64 | | _ when n < 10 -> " " 65 | | _ when n < 100 -> " " 66 | | _ when n < 1000 -> " " 67 | | _ -> "" 68 | 69 | let create_string (char : string) (length : int) : string = 70 | Array.make length char 71 | |> Array.to_list 72 | |> String.concat "" 73 | 74 | let create_type_mapping (program : program) : type_mapping = 75 | let type_map : type_mapping = Hashtbl.create 53 in 76 | let _ = match program with 77 | | TypedInfraredProgram (statements, env) -> 78 | List.iter (fun statement -> walk_statement statement env type_map) statements 79 | | _ -> () 80 | in 81 | type_map 82 | 83 | let pp_types_within_file ?padding:(padding=2) (file : string) (program : program) : unit = 84 | let type_map = create_type_mapping program in 85 | let padding = String.make padding ' ' in 86 | let file_underline = create_string "╍" (String.length file) in 87 | let source = Fs.read_file file in 88 | let lines = split source in 89 | let line_strs = List.mapi (fun i line -> 90 | let line_number = i + 1 in 91 | let type_data_maybe = get_type_data type_map line_number in 92 | let type_line = match type_data_maybe with 93 | | Some (loc, d_type) -> 94 | let open Flow_parser.Loc in 95 | let underline_spacing = String.make (loc.start.column + 1) ' ' in 96 | let underline = create_string "▔" (loc._end.column - loc.start.column) 97 | in 98 | Printf.sprintf "\n%s%s%s%s %s" 99 | (pad line_number) 100 | (pad_of_number line_number) 101 | underline_spacing 102 | (underline |> Chalk.green |> Chalk.bold) 103 | ((Printer.string_of_data_type d_type ~depth:2) |> Chalk.green |> Chalk.bold) 104 | | None -> "" 105 | in 106 | Printf.sprintf "%s%s%s%s%s" 107 | (pad line_number) 108 | (Chalk.gray (string_of_int line_number)) 109 | padding 110 | line 111 | type_line 112 | ) lines 113 | in 114 | Printf.printf "%s\n%s\n%s\n\n" 115 | (padding ^ (Chalk.bold file)) 116 | (padding ^ (Chalk.bold file_underline)) 117 | (String.concat "\n" line_strs) 118 | 119 | end 120 | -------------------------------------------------------------------------------- /Infrared/commands/check_command.ml: -------------------------------------------------------------------------------- 1 | open InfraredParser 2 | open InfraredCompiler 3 | open InfraredUtils 4 | open Ast 5 | 6 | (* @TODO: Once we start working on the checker, this type will become useful. 7 | * @NOTE: I don't think we need to encode type "errors" in the typing routine. 8 | * Like a type contradiction isn't something we have a type for in our AST. 9 | *) 10 | type typing_result = 11 | | TypedProgram of string * program (* file, TypedInfraredProgram *) 12 | | ParsingError of parser_result 13 | 14 | and parser_result = 15 | | Success of string * program 16 | | Fail of string * int * string (* file, Infrared_parsing_error *) 17 | | Nil of string 18 | 19 | let parse_file (file : string) : parser_result = 20 | let open InfraredParser.Parser in 21 | let source = Fs.read_file file in 22 | try 23 | let prog = Parser.parse_source ~file ~source in 24 | Success (file, prog) 25 | with 26 | | Infrared_parsing_error (count, message) -> 27 | Fail (file, count, message) 28 | | _ -> 29 | Nil file 30 | 31 | let print_result_summary start_time files err_files err_count : unit = 32 | let end_time = Unix.gettimeofday () in 33 | Printf.printf "\n%sChecked %s files in %ss" 34 | (Chalk.green " ↗ ") 35 | (files 36 | |> List.length 37 | |> string_of_int 38 | |> Chalk.green) 39 | (String.sub (string_of_float (end_time -. start_time)) 0 4); 40 | if err_files > 0 || err_count > 0 then 41 | Printf.printf "\n%sFailed to parse %s files with %s errors" 42 | (Chalk.red " ↘ ") 43 | (err_files 44 | |> string_of_int 45 | |> Chalk.red) 46 | (err_count 47 | |> string_of_int 48 | |> Chalk.red); 49 | Printf.printf "\n\n" 50 | 51 | let check_file (file : string) : typing_result = 52 | let parsing_output = parse_file file in 53 | let typed_program : typing_result = match parsing_output with 54 | | Success (file, program) -> 55 | let typed_program = Compiler.assign_types ~file ~program in 56 | TypedProgram (file, typed_program) 57 | | _ -> ParsingError parsing_output 58 | in 59 | typed_program 60 | 61 | let string_of_parser_result (res : parser_result) : string = 62 | let open Chalk in 63 | match res with 64 | | Success (file, _prog) -> 65 | Printf.sprintf "%s %s\n" 66 | (" Pass " |> green |> bold) 67 | (gray file) 68 | | Fail (file, _count, message) -> 69 | let failure = Printf.sprintf "%s %s\n" 70 | (" Fail " |> red |> bold) 71 | (gray file) 72 | in 73 | Printf.sprintf "%s%s\n" failure message 74 | | Nil file -> 75 | Printf.sprintf "%s %s\n" 76 | (" Fatal " |> red |> bold) 77 | (gray file) 78 | 79 | let string_of_typing_result (res : typing_result) : string = 80 | let open Chalk in 81 | match res with 82 | | TypedProgram (file, _prog) -> 83 | Printf.sprintf "%s %s\n" 84 | (" Pass " |> green |> bold) 85 | (gray file) 86 | | ParsingError (parser_result) -> string_of_parser_result parser_result 87 | 88 | let check_files (files : string list) : unit = 89 | let start_time = Unix.gettimeofday () in 90 | let results = List.map (fun file -> check_file file) files in 91 | let result_strings = List.map string_of_typing_result results in 92 | let () = List.iter (fun str -> Printf.printf "%s" str) result_strings in 93 | let (err_files, err_count) = List.fold_left (fun acc res -> 94 | match res with 95 | | ParsingError parser_result -> 96 | ( 97 | match parser_result with 98 | | Fail (_file, count, _message) -> 99 | let (acc_f, acc_c) = acc in 100 | (acc_f + 1, acc_c + count) 101 | | Nil _file -> 102 | let (acc_f, acc_c) = acc in 103 | (acc_f + 1, acc_c) 104 | | _ -> acc 105 | ) 106 | | _ -> acc) 107 | (0, 0) results 108 | in 109 | print_result_summary start_time files err_files err_count 110 | 111 | let type_check ?flags:(flags=[]) args : unit = 112 | print_endline ""; 113 | if Utils.is_flag_set "debug" flags then 114 | Settings.debug_mode := true; 115 | if Utils.is_flag_set "show-types-in-console" flags then 116 | Settings.show_types_in_console := true; 117 | match args with 118 | | [] -> () 119 | | arg :: [] -> 120 | let paths = 121 | arg 122 | |> Fs.files_from_path 123 | |> List.rev 124 | in 125 | check_files paths 126 | | args -> 127 | let paths = 128 | args 129 | |> List.map Fs.files_from_path 130 | |> List.flatten 131 | |> List.rev 132 | in 133 | check_files paths 134 | 135 | let spec = Command.create 136 | ~name:"check" 137 | ~aliases:["ch"] 138 | ~doc:"Type check the given JavaScript files" 139 | ~flags:[ 140 | (Flag.create ~name:"--show-types-in-console" ~doc:"Show types in console"); 141 | (Flag.create ~name:"--debug" ~doc:"Show debug information, like AST transforms") 142 | ] 143 | 144 | let exec = type_check 145 | 146 | type t = 147 | { spec: Command.t 148 | ; exec: ?flags:string list -> string list -> unit 149 | } 150 | 151 | let command : t = 152 | { spec = spec 153 | ; exec = exec 154 | } 155 | -------------------------------------------------------------------------------- /InfraredParser/.merlin: -------------------------------------------------------------------------------- 1 | EXCLUDE_QUERY_DIR 2 | B /Users/nick/.opam/4.08.0/lib/base 3 | B /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 4 | B /Users/nick/.opam/4.08.0/lib/base/caml 5 | B /Users/nick/.opam/4.08.0/lib/base/md5 6 | B /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 7 | B /Users/nick/.opam/4.08.0/lib/base_bigstring 8 | B /Users/nick/.opam/4.08.0/lib/base_quickcheck 9 | B /Users/nick/.opam/4.08.0/lib/bin_prot 10 | B /Users/nick/.opam/4.08.0/lib/bin_prot/shape 11 | B /Users/nick/.opam/4.08.0/lib/bytes 12 | B /Users/nick/.opam/4.08.0/lib/core 13 | B /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 14 | B /Users/nick/.opam/4.08.0/lib/core_kernel 15 | B /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 16 | B /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 17 | B /Users/nick/.opam/4.08.0/lib/core_kernel/flags 18 | B /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 19 | B /Users/nick/.opam/4.08.0/lib/fieldslib 20 | B /Users/nick/.opam/4.08.0/lib/gen 21 | B /Users/nick/.opam/4.08.0/lib/jane-street-headers 22 | B /Users/nick/.opam/4.08.0/lib/ocaml 23 | B /Users/nick/.opam/4.08.0/lib/ocaml/threads 24 | B /Users/nick/.opam/4.08.0/lib/parsexp 25 | B /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 26 | B /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 27 | B /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 28 | B /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 29 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 30 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/common 31 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/config 32 | B /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 33 | B /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 34 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 35 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 36 | B /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 37 | B /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 38 | B /Users/nick/.opam/4.08.0/lib/sedlex 39 | B /Users/nick/.opam/4.08.0/lib/sexplib 40 | B /Users/nick/.opam/4.08.0/lib/sexplib/unix 41 | B /Users/nick/.opam/4.08.0/lib/sexplib0 42 | B /Users/nick/.opam/4.08.0/lib/spawn 43 | B /Users/nick/.opam/4.08.0/lib/splittable_random 44 | B /Users/nick/.opam/4.08.0/lib/stdio 45 | B /Users/nick/.opam/4.08.0/lib/time_now 46 | B /Users/nick/.opam/4.08.0/lib/typerep 47 | B /Users/nick/.opam/4.08.0/lib/uchar 48 | B /Users/nick/.opam/4.08.0/lib/variantslib 49 | B /Users/nick/.opam/4.08.0/lib/wtf8 50 | B ../_build/default/InfraredParser/.InfraredParser.objs/byte 51 | B ../_build/default/InfraredParser/flow_parser/lib/.Flow_parser.objs/byte 52 | B ../_build/default/InfraredUtils/.InfraredUtils.objs/byte 53 | S /Users/nick/.opam/4.08.0/lib/base 54 | S /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 55 | S /Users/nick/.opam/4.08.0/lib/base/caml 56 | S /Users/nick/.opam/4.08.0/lib/base/md5 57 | S /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 58 | S /Users/nick/.opam/4.08.0/lib/base_bigstring 59 | S /Users/nick/.opam/4.08.0/lib/base_quickcheck 60 | S /Users/nick/.opam/4.08.0/lib/bin_prot 61 | S /Users/nick/.opam/4.08.0/lib/bin_prot/shape 62 | S /Users/nick/.opam/4.08.0/lib/bytes 63 | S /Users/nick/.opam/4.08.0/lib/core 64 | S /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 65 | S /Users/nick/.opam/4.08.0/lib/core_kernel 66 | S /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 67 | S /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 68 | S /Users/nick/.opam/4.08.0/lib/core_kernel/flags 69 | S /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 70 | S /Users/nick/.opam/4.08.0/lib/fieldslib 71 | S /Users/nick/.opam/4.08.0/lib/gen 72 | S /Users/nick/.opam/4.08.0/lib/jane-street-headers 73 | S /Users/nick/.opam/4.08.0/lib/ocaml 74 | S /Users/nick/.opam/4.08.0/lib/ocaml/threads 75 | S /Users/nick/.opam/4.08.0/lib/parsexp 76 | S /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 77 | S /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 78 | S /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 79 | S /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 80 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 81 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/common 82 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/config 83 | S /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 84 | S /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 85 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 86 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 87 | S /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 88 | S /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 89 | S /Users/nick/.opam/4.08.0/lib/sedlex 90 | S /Users/nick/.opam/4.08.0/lib/sexplib 91 | S /Users/nick/.opam/4.08.0/lib/sexplib/unix 92 | S /Users/nick/.opam/4.08.0/lib/sexplib0 93 | S /Users/nick/.opam/4.08.0/lib/spawn 94 | S /Users/nick/.opam/4.08.0/lib/splittable_random 95 | S /Users/nick/.opam/4.08.0/lib/stdio 96 | S /Users/nick/.opam/4.08.0/lib/time_now 97 | S /Users/nick/.opam/4.08.0/lib/typerep 98 | S /Users/nick/.opam/4.08.0/lib/uchar 99 | S /Users/nick/.opam/4.08.0/lib/variantslib 100 | S /Users/nick/.opam/4.08.0/lib/wtf8 101 | S . 102 | S flow_parser/lib 103 | S parsers 104 | S parsers/Flow 105 | S transformers 106 | S ../InfraredUtils 107 | FLG -open InfraredParser -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs 108 | -------------------------------------------------------------------------------- /InfraredCompiler/.merlin: -------------------------------------------------------------------------------- 1 | EXCLUDE_QUERY_DIR 2 | B /Users/nick/.opam/4.08.0/lib/base 3 | B /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 4 | B /Users/nick/.opam/4.08.0/lib/base/caml 5 | B /Users/nick/.opam/4.08.0/lib/base/md5 6 | B /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 7 | B /Users/nick/.opam/4.08.0/lib/base_bigstring 8 | B /Users/nick/.opam/4.08.0/lib/base_quickcheck 9 | B /Users/nick/.opam/4.08.0/lib/bin_prot 10 | B /Users/nick/.opam/4.08.0/lib/bin_prot/shape 11 | B /Users/nick/.opam/4.08.0/lib/bytes 12 | B /Users/nick/.opam/4.08.0/lib/core 13 | B /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 14 | B /Users/nick/.opam/4.08.0/lib/core_kernel 15 | B /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 16 | B /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 17 | B /Users/nick/.opam/4.08.0/lib/core_kernel/flags 18 | B /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 19 | B /Users/nick/.opam/4.08.0/lib/fieldslib 20 | B /Users/nick/.opam/4.08.0/lib/gen 21 | B /Users/nick/.opam/4.08.0/lib/jane-street-headers 22 | B /Users/nick/.opam/4.08.0/lib/ocaml 23 | B /Users/nick/.opam/4.08.0/lib/ocaml/threads 24 | B /Users/nick/.opam/4.08.0/lib/parsexp 25 | B /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 26 | B /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 27 | B /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 28 | B /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 29 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 30 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/common 31 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/config 32 | B /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 33 | B /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 34 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 35 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 36 | B /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 37 | B /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 38 | B /Users/nick/.opam/4.08.0/lib/sedlex 39 | B /Users/nick/.opam/4.08.0/lib/sexplib 40 | B /Users/nick/.opam/4.08.0/lib/sexplib/unix 41 | B /Users/nick/.opam/4.08.0/lib/sexplib0 42 | B /Users/nick/.opam/4.08.0/lib/spawn 43 | B /Users/nick/.opam/4.08.0/lib/splittable_random 44 | B /Users/nick/.opam/4.08.0/lib/stdio 45 | B /Users/nick/.opam/4.08.0/lib/time_now 46 | B /Users/nick/.opam/4.08.0/lib/typerep 47 | B /Users/nick/.opam/4.08.0/lib/uchar 48 | B /Users/nick/.opam/4.08.0/lib/variantslib 49 | B /Users/nick/.opam/4.08.0/lib/wtf8 50 | B ../_build/default/InfraredCompiler/.InfraredCompiler.objs/byte 51 | B ../_build/default/InfraredParser/.InfraredParser.objs/byte 52 | B ../_build/default/InfraredParser/flow_parser/lib/.Flow_parser.objs/byte 53 | B ../_build/default/InfraredUtils/.InfraredUtils.objs/byte 54 | S /Users/nick/.opam/4.08.0/lib/base 55 | S /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 56 | S /Users/nick/.opam/4.08.0/lib/base/caml 57 | S /Users/nick/.opam/4.08.0/lib/base/md5 58 | S /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 59 | S /Users/nick/.opam/4.08.0/lib/base_bigstring 60 | S /Users/nick/.opam/4.08.0/lib/base_quickcheck 61 | S /Users/nick/.opam/4.08.0/lib/bin_prot 62 | S /Users/nick/.opam/4.08.0/lib/bin_prot/shape 63 | S /Users/nick/.opam/4.08.0/lib/bytes 64 | S /Users/nick/.opam/4.08.0/lib/core 65 | S /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 66 | S /Users/nick/.opam/4.08.0/lib/core_kernel 67 | S /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 68 | S /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 69 | S /Users/nick/.opam/4.08.0/lib/core_kernel/flags 70 | S /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 71 | S /Users/nick/.opam/4.08.0/lib/fieldslib 72 | S /Users/nick/.opam/4.08.0/lib/gen 73 | S /Users/nick/.opam/4.08.0/lib/jane-street-headers 74 | S /Users/nick/.opam/4.08.0/lib/ocaml 75 | S /Users/nick/.opam/4.08.0/lib/ocaml/threads 76 | S /Users/nick/.opam/4.08.0/lib/parsexp 77 | S /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 78 | S /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 79 | S /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 80 | S /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 81 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 82 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/common 83 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/config 84 | S /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 85 | S /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 86 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 87 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 88 | S /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 89 | S /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 90 | S /Users/nick/.opam/4.08.0/lib/sedlex 91 | S /Users/nick/.opam/4.08.0/lib/sexplib 92 | S /Users/nick/.opam/4.08.0/lib/sexplib/unix 93 | S /Users/nick/.opam/4.08.0/lib/sexplib0 94 | S /Users/nick/.opam/4.08.0/lib/spawn 95 | S /Users/nick/.opam/4.08.0/lib/splittable_random 96 | S /Users/nick/.opam/4.08.0/lib/stdio 97 | S /Users/nick/.opam/4.08.0/lib/time_now 98 | S /Users/nick/.opam/4.08.0/lib/typerep 99 | S /Users/nick/.opam/4.08.0/lib/uchar 100 | S /Users/nick/.opam/4.08.0/lib/variantslib 101 | S /Users/nick/.opam/4.08.0/lib/wtf8 102 | S . 103 | S transformers 104 | S ../InfraredParser 105 | S ../InfraredParser/flow_parser/lib 106 | S ../InfraredUtils 107 | FLG -open InfraredCompiler -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs 108 | -------------------------------------------------------------------------------- /Infrared/.merlin: -------------------------------------------------------------------------------- 1 | EXCLUDE_QUERY_DIR 2 | B /Users/nick/.opam/4.08.0/lib/base 3 | B /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 4 | B /Users/nick/.opam/4.08.0/lib/base/caml 5 | B /Users/nick/.opam/4.08.0/lib/base/md5 6 | B /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 7 | B /Users/nick/.opam/4.08.0/lib/base_bigstring 8 | B /Users/nick/.opam/4.08.0/lib/base_quickcheck 9 | B /Users/nick/.opam/4.08.0/lib/bin_prot 10 | B /Users/nick/.opam/4.08.0/lib/bin_prot/shape 11 | B /Users/nick/.opam/4.08.0/lib/bytes 12 | B /Users/nick/.opam/4.08.0/lib/core 13 | B /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 14 | B /Users/nick/.opam/4.08.0/lib/core_kernel 15 | B /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 16 | B /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 17 | B /Users/nick/.opam/4.08.0/lib/core_kernel/flags 18 | B /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 19 | B /Users/nick/.opam/4.08.0/lib/fieldslib 20 | B /Users/nick/.opam/4.08.0/lib/gen 21 | B /Users/nick/.opam/4.08.0/lib/jane-street-headers 22 | B /Users/nick/.opam/4.08.0/lib/ocaml 23 | B /Users/nick/.opam/4.08.0/lib/ocaml/threads 24 | B /Users/nick/.opam/4.08.0/lib/parsexp 25 | B /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 26 | B /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 27 | B /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 28 | B /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 29 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 30 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/common 31 | B /Users/nick/.opam/4.08.0/lib/ppx_expect/config 32 | B /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 33 | B /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 34 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 35 | B /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 36 | B /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 37 | B /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 38 | B /Users/nick/.opam/4.08.0/lib/sedlex 39 | B /Users/nick/.opam/4.08.0/lib/sexplib 40 | B /Users/nick/.opam/4.08.0/lib/sexplib/unix 41 | B /Users/nick/.opam/4.08.0/lib/sexplib0 42 | B /Users/nick/.opam/4.08.0/lib/spawn 43 | B /Users/nick/.opam/4.08.0/lib/splittable_random 44 | B /Users/nick/.opam/4.08.0/lib/stdio 45 | B /Users/nick/.opam/4.08.0/lib/time_now 46 | B /Users/nick/.opam/4.08.0/lib/typerep 47 | B /Users/nick/.opam/4.08.0/lib/uchar 48 | B /Users/nick/.opam/4.08.0/lib/variantslib 49 | B /Users/nick/.opam/4.08.0/lib/wtf8 50 | B ../_build/default/Infrared/.main.eobjs/byte 51 | B ../_build/default/InfraredCompiler/.InfraredCompiler.objs/byte 52 | B ../_build/default/InfraredParser/.InfraredParser.objs/byte 53 | B ../_build/default/InfraredParser/flow_parser/lib/.Flow_parser.objs/byte 54 | B ../_build/default/InfraredUtils/.InfraredUtils.objs/byte 55 | S /Users/nick/.opam/4.08.0/lib/base 56 | S /Users/nick/.opam/4.08.0/lib/base/base_internalhash_types 57 | S /Users/nick/.opam/4.08.0/lib/base/caml 58 | S /Users/nick/.opam/4.08.0/lib/base/md5 59 | S /Users/nick/.opam/4.08.0/lib/base/shadow_stdlib 60 | S /Users/nick/.opam/4.08.0/lib/base_bigstring 61 | S /Users/nick/.opam/4.08.0/lib/base_quickcheck 62 | S /Users/nick/.opam/4.08.0/lib/bin_prot 63 | S /Users/nick/.opam/4.08.0/lib/bin_prot/shape 64 | S /Users/nick/.opam/4.08.0/lib/bytes 65 | S /Users/nick/.opam/4.08.0/lib/core 66 | S /Users/nick/.opam/4.08.0/lib/core/error_checking_mutex 67 | S /Users/nick/.opam/4.08.0/lib/core_kernel 68 | S /Users/nick/.opam/4.08.0/lib/core_kernel/base_for_tests 69 | S /Users/nick/.opam/4.08.0/lib/core_kernel/bounded_int_table 70 | S /Users/nick/.opam/4.08.0/lib/core_kernel/flags 71 | S /Users/nick/.opam/4.08.0/lib/core_kernel/version_util 72 | S /Users/nick/.opam/4.08.0/lib/fieldslib 73 | S /Users/nick/.opam/4.08.0/lib/gen 74 | S /Users/nick/.opam/4.08.0/lib/jane-street-headers 75 | S /Users/nick/.opam/4.08.0/lib/ocaml 76 | S /Users/nick/.opam/4.08.0/lib/ocaml/threads 77 | S /Users/nick/.opam/4.08.0/lib/parsexp 78 | S /Users/nick/.opam/4.08.0/lib/ppx_assert/runtime-lib 79 | S /Users/nick/.opam/4.08.0/lib/ppx_bench/runtime-lib 80 | S /Users/nick/.opam/4.08.0/lib/ppx_compare/runtime-lib 81 | S /Users/nick/.opam/4.08.0/lib/ppx_enumerate/runtime-lib 82 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/collector 83 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/common 84 | S /Users/nick/.opam/4.08.0/lib/ppx_expect/config 85 | S /Users/nick/.opam/4.08.0/lib/ppx_hash/runtime-lib 86 | S /Users/nick/.opam/4.08.0/lib/ppx_here/runtime-lib 87 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/config 88 | S /Users/nick/.opam/4.08.0/lib/ppx_inline_test/runtime-lib 89 | S /Users/nick/.opam/4.08.0/lib/ppx_module_timer/runtime 90 | S /Users/nick/.opam/4.08.0/lib/ppx_sexp_conv/runtime-lib 91 | S /Users/nick/.opam/4.08.0/lib/sedlex 92 | S /Users/nick/.opam/4.08.0/lib/sexplib 93 | S /Users/nick/.opam/4.08.0/lib/sexplib/unix 94 | S /Users/nick/.opam/4.08.0/lib/sexplib0 95 | S /Users/nick/.opam/4.08.0/lib/spawn 96 | S /Users/nick/.opam/4.08.0/lib/splittable_random 97 | S /Users/nick/.opam/4.08.0/lib/stdio 98 | S /Users/nick/.opam/4.08.0/lib/time_now 99 | S /Users/nick/.opam/4.08.0/lib/typerep 100 | S /Users/nick/.opam/4.08.0/lib/uchar 101 | S /Users/nick/.opam/4.08.0/lib/variantslib 102 | S /Users/nick/.opam/4.08.0/lib/wtf8 103 | S . 104 | S commands 105 | S ../InfraredCompiler 106 | S ../InfraredParser 107 | S ../InfraredParser/flow_parser/lib 108 | S ../InfraredUtils 109 | FLG -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs 110 | -------------------------------------------------------------------------------- /InfraredCompiler/transformers/uniquify.ml: -------------------------------------------------------------------------------- 1 | open InfraredUtils 2 | open InfraredParser.Ast 3 | open InfraredAst 4 | 5 | exception Unexpected_compiler_phase of string 6 | 7 | type env_t = (identifier', string) Hashtbl.t 8 | 9 | (* Return the latest hash for a given variable variable. Since the variables 10 | * are stored in the hashtable, a failed lookup means this variable was never 11 | * declared, so there's a chance its a global. *) 12 | let get_hash (tbl : env_t) (key : identifier') : string = 13 | try Hashtbl.find tbl key 14 | with _ -> "" 15 | 16 | let get_hashed_variable id hash = 17 | match hash with 18 | | "" -> id 19 | | _ -> id ^ "_" ^ hash 20 | 21 | let rec uniquify_statements (statements : statement list) (env : env_t) : statement list = 22 | let statements' = List.map (fun s -> uniquify_function_declaration_statement s env) statements in 23 | let statements'' = List.map (fun s -> uniquify_all_other_statement s env) statements' in 24 | statements'' 25 | 26 | and uniquify_function_declaration_statement (statement : statement) (env : env_t) : statement = 27 | let (loc, statement) = statement in 28 | match statement with 29 | | FunctionDeclaration ((name_loc, name), params, body) -> 30 | let hash = Utils.generate_hash () in 31 | Hashtbl.replace env name hash; 32 | let name' = get_hashed_variable name hash in 33 | (* @NOTE: Environment Copying 34 | * Copying the environment for the function body is what lets us remove 35 | * variable shadowing. This is because we won't overwrite any variables 36 | * in the current environment, since this inner closure is contained. *) 37 | let env' = Hashtbl.copy env in 38 | let params' = List.map (fun (param_loc, param) -> 39 | let hash = Utils.generate_hash () in 40 | Hashtbl.replace env' param hash; 41 | let param' = get_hashed_variable param hash in 42 | (param_loc, param') 43 | ) params 44 | in 45 | let body' = uniquify_statements body env' in 46 | (loc, FunctionDeclaration ((name_loc, name'), params', body')) 47 | | _ -> (loc, statement) 48 | 49 | and uniquify_all_other_statement (statement : statement) (env : env_t) : statement = 50 | let (loc, statement) = statement in 51 | match statement with 52 | | VariableDeclaration ((id_loc, id), expression) -> 53 | let hash = Utils.generate_hash () in 54 | Hashtbl.replace env id hash; 55 | let id' = get_hashed_variable id hash in 56 | let expression' = uniquify_expression expression env in 57 | (loc, VariableDeclaration ((id_loc, id'), expression')) 58 | | Expression expr -> 59 | let expression' = uniquify_expression expr env in 60 | (loc, Expression expression') 61 | | Return expr -> 62 | let expression' = uniquify_expression expr env in 63 | (loc, Return expression') 64 | | Block statements -> 65 | (* @NOTE: Block Scopes 66 | * @SEE: Environment Copying 67 | * Technically block scopes are only applied with `let` or `const` variables. 68 | * I should eventually come back to clear this up, but for now let's ignore it 69 | * and assume all variables are declared this way. 70 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block#block_scoping_rules_with_var_or_function_declaration_in_non-strict_mode *) 71 | let env' = Hashtbl.copy env in 72 | let statements' = uniquify_statements statements env' in 73 | (loc, Block statements') 74 | | If (expr, s1, s2) -> 75 | let expr' = uniquify_expression expr env in 76 | let s1' = uniquify_all_other_statement s1 env in 77 | let s2' = uniquify_all_other_statement s2 env in 78 | (loc, If (expr', s1', s2')) 79 | | FunctionDeclaration (name, args, body) -> 80 | (loc, FunctionDeclaration (name, args, body)) 81 | 82 | and uniquify_expression (expression : expression) (env : env_t) : expression = 83 | let (loc, expression) = expression in 84 | match expression with 85 | | Variable (id_loc, id) -> 86 | let hash = get_hash env id in 87 | let id' = get_hashed_variable id hash in 88 | (loc, Variable (id_loc, id')) 89 | | BinaryOperation (binop, left, right) -> 90 | let left' = uniquify_expression left env in 91 | let right' = uniquify_expression right env in 92 | (loc, BinaryOperation (binop, left', right')) 93 | | Object pairs -> 94 | let pairs' = List.map (fun pair -> 95 | let (key, value) = pair in 96 | let value' = uniquify_expression value env in 97 | (key, value') 98 | ) pairs 99 | in 100 | (loc, Object pairs') 101 | | Access (e1, e2) -> 102 | let e1' = uniquify_expression e1 env in 103 | let e2' = uniquify_property e2 env in 104 | (loc, Access (e1', e2')) 105 | | Call (callee, args) -> 106 | let callee' = uniquify_expression callee env in 107 | let args' = List.map (fun arg -> uniquify_expression arg env) args in 108 | (loc, Call (callee', args')) 109 | | _ -> (loc, expression) 110 | 111 | and uniquify_property (prop : property) (env : env_t) : property = 112 | match prop with 113 | | PropertyExpression expr -> PropertyExpression (uniquify_expression expr env) 114 | | PropertyIdentifier id -> PropertyIdentifier id 115 | 116 | let transform (program : program) : program = 117 | let env = Hashtbl.create 53 in 118 | match program with 119 | | InfraredProgram (statements) -> 120 | let statements' = uniquify_statements statements env in 121 | InfraredProgram statements' 122 | | _ -> raise (Unexpected_compiler_phase "Expected InfraredProgram") 123 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/parser_common.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | open Parser_env 9 | open Ast 10 | module Error = Parse_error 11 | 12 | type pattern_errors = { 13 | if_expr: (Loc.t * Parse_error.t) list; 14 | if_patt: (Loc.t * Parse_error.t) list; 15 | } 16 | 17 | type pattern_cover = 18 | | Cover_expr of Loc.t Expression.t 19 | | Cover_patt of Loc.t Expression.t * pattern_errors 20 | 21 | module type PARSER = sig 22 | val program : env -> Loc.t program 23 | val statement : env -> Loc.t Statement.t 24 | val statement_list_item : ?decorators:Loc.t Expression.t list -> env -> Loc.t Statement.t 25 | val statement_list : term_fn:(Token.t -> bool) -> env -> Loc.t Statement.t list 26 | val statement_list_with_directives : term_fn:(Token.t -> bool) -> env -> Loc.t Statement.t list * bool 27 | val module_body : term_fn:(Token.t -> bool) -> env -> Loc.t Statement.t list 28 | val expression : env -> Loc.t Expression.t 29 | val expression_or_pattern : env -> pattern_cover 30 | val conditional : env -> Loc.t Expression.t 31 | val assignment : env -> Loc.t Expression.t 32 | val left_hand_side : env -> Loc.t Expression.t 33 | val object_initializer : env -> Loc.t * Loc.t Expression.Object.t * pattern_errors 34 | val identifier : ?restricted_error:Error.t -> env -> Loc.t Identifier.t 35 | val identifier_with_type : env -> ?no_optional:bool -> Error.t -> Loc.t * Loc.t Pattern.Identifier.t 36 | val assert_identifier_name_is_identifier : 37 | ?restricted_error:Error.t -> env -> Loc.t * string -> unit 38 | val block_body : env -> Loc.t * Loc.t Statement.Block.t 39 | val function_block_body : env -> Loc.t * Loc.t Statement.Block.t * bool 40 | val jsx_element_or_fragment : 41 | env -> Loc.t * [`Element of Loc.t JSX.element | `Fragment of Loc.t JSX.fragment] 42 | val pattern : env -> Error.t -> Loc.t Pattern.t 43 | val pattern_from_expr : env -> Loc.t Expression.t -> Loc.t Pattern.t 44 | val object_key : ?class_body: bool -> env -> Loc.t * Loc.t Expression.Object.Property.key 45 | val class_declaration : env -> Loc.t Expression.t list -> Loc.t Statement.t 46 | val class_expression : env -> Loc.t Expression.t 47 | val is_assignable_lhs : Loc.t Expression.t -> bool 48 | end 49 | 50 | (* IdentifierName - https://tc39.github.io/ecma262/#prod-IdentifierName *) 51 | let identifier_name env = 52 | let open Token in 53 | let loc = Peek.loc env in 54 | let name = match Peek.token env with 55 | (* obviously, Identifier is a valid IdentifierName *) 56 | | T_IDENTIFIER { value; _ } -> value 57 | (* keywords are also IdentifierNames *) 58 | | T_AWAIT -> "await" 59 | | T_BREAK -> "break" 60 | | T_CASE -> "case" 61 | | T_CATCH -> "catch" 62 | | T_CLASS -> "class" 63 | | T_CONST -> "const" 64 | | T_CONTINUE -> "continue" 65 | | T_DEBUGGER -> "debugger" 66 | | T_DEFAULT -> "default" 67 | | T_DELETE -> "delete" 68 | | T_DO -> "do" 69 | | T_ELSE -> "else" 70 | | T_EXPORT -> "export" 71 | | T_EXTENDS -> "extends" 72 | | T_FINALLY -> "finally" 73 | | T_FOR -> "for" 74 | | T_FUNCTION -> "function" 75 | | T_IF -> "if" 76 | | T_IMPORT -> "import" 77 | | T_IN -> "in" 78 | | T_INSTANCEOF -> "instanceof" 79 | | T_NEW -> "new" 80 | | T_RETURN -> "return" 81 | | T_SUPER -> "super" 82 | | T_SWITCH -> "switch" 83 | | T_THIS -> "this" 84 | | T_THROW -> "throw" 85 | | T_TRY -> "try" 86 | | T_TYPEOF -> "typeof" 87 | | T_VAR -> "var" 88 | | T_VOID -> "void" 89 | | T_WHILE -> "while" 90 | | T_WITH -> "with" 91 | | T_YIELD -> "yield" 92 | (* FutureReservedWord *) 93 | | T_ENUM -> "enum" 94 | | T_LET -> "let" 95 | | T_STATIC -> "static" 96 | | T_INTERFACE -> "interface" 97 | | T_IMPLEMENTS -> "implements" 98 | | T_PACKAGE -> "package" 99 | | T_PRIVATE -> "private" 100 | | T_PROTECTED -> "protected" 101 | | T_PUBLIC -> "public" 102 | (* NullLiteral *) 103 | | T_NULL -> "null" 104 | (* BooleanLiteral *) 105 | | T_TRUE -> "true" 106 | | T_FALSE -> "false" 107 | (* Flow-specific stuff *) 108 | | T_DECLARE -> "declare" 109 | | T_TYPE -> "type" 110 | | T_OPAQUE -> "opaque" 111 | | T_ANY_TYPE -> "any" 112 | | T_MIXED_TYPE -> "mixed" 113 | | T_EMPTY_TYPE -> "empty" 114 | | T_BOOLEAN_TYPE BOOL -> "bool" 115 | | T_BOOLEAN_TYPE BOOLEAN -> "boolean" 116 | | T_NUMBER_TYPE -> "number" 117 | | T_STRING_TYPE -> "string" 118 | | T_VOID_TYPE -> "void" 119 | (* Contextual stuff *) 120 | | T_OF -> "of" 121 | | T_ASYNC -> "async" 122 | (* punctuators, types, literals, etc are not identifiers *) 123 | | _ -> error_unexpected env; "" 124 | in 125 | Eat.token env; 126 | loc, name 127 | 128 | let assert_identifier_name_is_type_identifier env (loc, name) = 129 | if is_reserved_type name then error_at env (loc, Parse_error.UnexpectedReservedType) 130 | 131 | (** 132 | * The abstract operation IsLabelledFunction 133 | * 134 | * https://tc39.github.io/ecma262/#sec-islabelledfunction 135 | *) 136 | let rec is_labelled_function = function 137 | | _, Ast.Statement.Labeled { Ast.Statement.Labeled.body; _ } -> 138 | begin match body with 139 | | _, Ast.Statement.FunctionDeclaration _ -> true 140 | | _ -> is_labelled_function body 141 | end 142 | | _ -> 143 | false 144 | 145 | let with_loc ?start_loc fn env = 146 | let start_loc = match start_loc with 147 | | Some x -> x 148 | | None -> Peek.loc env 149 | in 150 | let result = fn env in 151 | let loc = match last_loc env with 152 | | Some end_loc -> Loc.btwn start_loc end_loc 153 | | None -> start_loc 154 | in 155 | loc, result 156 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/parser_env.mli: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | (* This module provides a layer between the lexer and the parser which includes 9 | * some parser state and some lexer state *) 10 | 11 | module SSet : Set.S with type t = Set.Make(String).t 12 | 13 | module Lex_mode : sig 14 | type t = 15 | | NORMAL 16 | | TYPE 17 | | JSX_TAG 18 | | JSX_CHILD 19 | | TEMPLATE 20 | | REGEXP 21 | val debug_string_of_lex_mode: t -> string 22 | end 23 | 24 | type token_sink_result = { 25 | token_loc: Loc.t; 26 | token: Token.t; 27 | token_context: Lex_mode.t; 28 | } 29 | 30 | type parse_options = { 31 | esproposal_class_instance_fields: bool; 32 | esproposal_class_static_fields: bool; 33 | esproposal_decorators: bool; 34 | esproposal_export_star_as: bool; 35 | esproposal_optional_chaining: bool; 36 | types: bool; 37 | types_in_comments: bool; 38 | use_strict: bool; 39 | } 40 | val default_parse_options : parse_options 41 | 42 | type env 43 | 44 | type allowed_super = 45 | | No_super 46 | | Super_prop 47 | | Super_prop_or_call 48 | 49 | (* constructor: *) 50 | val init_env : 51 | ?token_sink:(token_sink_result -> unit) option 52 | -> ?parse_options:parse_options option 53 | -> File_key.t option 54 | -> string 55 | -> env 56 | 57 | (* getters: *) 58 | val in_strict_mode : env -> bool 59 | val last_loc : env -> Loc.t option 60 | val last_token : env -> Token.t option 61 | val in_export : env -> bool 62 | val labels : env -> SSet.t 63 | val comments : env -> Loc.t Ast.Comment.t list 64 | val in_loop : env -> bool 65 | val in_switch : env -> bool 66 | val in_formal_parameters : env -> bool 67 | val in_function : env -> bool 68 | val allow_yield : env -> bool 69 | val allow_await: env -> bool 70 | val allow_directive : env -> bool 71 | val allow_super : env -> allowed_super 72 | val no_in : env -> bool 73 | val no_call : env -> bool 74 | val no_let : env -> bool 75 | val no_anon_function_type : env -> bool 76 | val no_new : env -> bool 77 | val errors : env -> (Loc.t * Parse_error.t) list 78 | val parse_options : env -> parse_options 79 | val source : env -> File_key.t option 80 | val should_parse_types : env -> bool 81 | 82 | (* mutators: *) 83 | val error_at : env -> Loc.t * Parse_error.t -> unit 84 | val error : env -> Parse_error.t -> unit 85 | val error_unexpected : env -> unit 86 | val error_on_decorators : env -> (Loc.t * 'a) list -> unit 87 | val strict_error : env -> Parse_error.t -> unit 88 | val strict_error_at : env -> Loc.t * Parse_error.t -> unit 89 | val function_as_statement_error_at : env -> Loc.t -> unit 90 | val comment_list : env -> Loc.t Ast.Comment.t list -> unit 91 | val error_list : env -> (Loc.t * Parse_error.t) list -> unit 92 | val record_export: env -> Loc.t * string -> unit 93 | val enter_class : env -> unit 94 | val exit_class : env -> unit 95 | val add_declared_private : env -> string -> unit 96 | val add_used_private : env -> string -> Loc.t -> unit 97 | 98 | (* functional operations -- these return shallow copies, so future mutations to 99 | * the returned env will also affect the original: *) 100 | val with_strict : bool -> env -> env 101 | val with_in_formal_parameters : bool -> env -> env 102 | val with_in_function : bool -> env -> env 103 | val with_allow_yield : bool -> env -> env 104 | val with_allow_await : bool -> env -> env 105 | val with_allow_directive : bool -> env -> env 106 | val with_allow_super : allowed_super -> env -> env 107 | val with_no_let : bool -> env -> env 108 | val with_in_loop : bool -> env -> env 109 | val with_no_in : bool -> env -> env 110 | val with_no_anon_function_type : bool -> env -> env 111 | val with_no_new : bool -> env -> env 112 | val with_in_switch : bool -> env -> env 113 | val with_in_export : bool -> env -> env 114 | val with_no_call : bool -> env -> env 115 | val with_error_callback : (env -> Parse_error.t -> unit) -> env -> env 116 | 117 | val without_error_callback : env -> env 118 | 119 | val add_label : env -> string -> env 120 | val enter_function : env -> async:bool -> generator:bool -> env 121 | 122 | val is_reserved : string -> bool 123 | val is_future_reserved : string -> bool 124 | val is_strict_reserved : string -> bool 125 | val token_is_strict_reserved : Token.t -> bool 126 | val is_restricted : string -> bool 127 | val is_reserved_type : string -> bool 128 | val token_is_restricted : Token.t -> bool 129 | 130 | module Peek : sig 131 | val token : env -> Token.t 132 | val loc : env -> Loc.t 133 | val errors : env -> (Loc.t * Parse_error.t) list 134 | val comments : env -> Loc.t Ast.Comment.t list 135 | val is_line_terminator : env -> bool 136 | val is_implicit_semicolon : env -> bool 137 | val is_identifier : env -> bool 138 | val is_type_identifier : env -> bool 139 | val is_identifier_name : env -> bool 140 | val is_function : env -> bool 141 | val is_class : env -> bool 142 | 143 | val ith_token : i:int -> env -> Token.t 144 | val ith_loc : i:int -> env -> Loc.t 145 | val ith_errors : i:int -> env -> (Loc.t * Parse_error.t) list 146 | val ith_comments : i:int -> env -> Loc.t Ast.Comment.t list 147 | val ith_is_identifier : i:int -> env -> bool 148 | val ith_is_identifier_name : i:int -> env -> bool 149 | val ith_is_type_identifier : i:int -> env -> bool 150 | end 151 | 152 | module Eat : sig 153 | val token : env -> unit 154 | val push_lex_mode : env -> Lex_mode.t -> unit 155 | val pop_lex_mode : env -> unit 156 | val double_pop_lex_mode : env -> unit 157 | val semicolon : env -> unit 158 | end 159 | 160 | module Expect : sig 161 | val token : env -> Token.t -> unit 162 | val identifier : env -> string -> unit 163 | val maybe : env -> Token.t -> bool 164 | end 165 | 166 | module Try : sig 167 | type 'a parse_result = 168 | | ParsedSuccessfully of 'a 169 | | FailedToParse 170 | 171 | exception Rollback 172 | 173 | val to_parse: env -> (env -> 'a) -> 'a parse_result 174 | end 175 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/flow_parser.install: -------------------------------------------------------------------------------- 1 | lib: [ 2 | "_build/install/default/lib/flow_parser/Flow_parser.a" {"Flow_parser.a"} 3 | "_build/install/default/lib/flow_parser/Flow_parser.cma" {"Flow_parser.cma"} 4 | "_build/install/default/lib/flow_parser/Flow_parser.cmxa" {"Flow_parser.cmxa"} 5 | "_build/install/default/lib/flow_parser/Flow_parser.cmxs" {"Flow_parser.cmxs"} 6 | "_build/install/default/lib/flow_parser/META" {"META"} 7 | "_build/install/default/lib/flow_parser/ast.ml" {"ast.ml"} 8 | "_build/install/default/lib/flow_parser/ast_utils.ml" {"ast_utils.ml"} 9 | "_build/install/default/lib/flow_parser/ast_utils.mli" {"ast_utils.mli"} 10 | "_build/install/default/lib/flow_parser/declaration_parser.ml" {"declaration_parser.ml"} 11 | "_build/install/default/lib/flow_parser/estree_translator.ml" {"estree_translator.ml"} 12 | "_build/install/default/lib/flow_parser/expression_parser.ml" {"expression_parser.ml"} 13 | "_build/install/default/lib/flow_parser/file_key.ml" {"file_key.ml"} 14 | "_build/install/default/lib/flow_parser/flow_parser.cmi" {"flow_parser.cmi"} 15 | "_build/install/default/lib/flow_parser/flow_parser.cmt" {"flow_parser.cmt"} 16 | "_build/install/default/lib/flow_parser/flow_parser.cmx" {"flow_parser.cmx"} 17 | "_build/install/default/lib/flow_parser/flow_parser.dune" {"flow_parser.dune"} 18 | "_build/install/default/lib/flow_parser/flow_parser.ml-gen" {"flow_parser.ml-gen"} 19 | "_build/install/default/lib/flow_parser/flow_parser__Ast.cmi" {"flow_parser__Ast.cmi"} 20 | "_build/install/default/lib/flow_parser/flow_parser__Ast.cmt" {"flow_parser__Ast.cmt"} 21 | "_build/install/default/lib/flow_parser/flow_parser__Ast.cmx" {"flow_parser__Ast.cmx"} 22 | "_build/install/default/lib/flow_parser/flow_parser__Ast_utils.cmi" {"flow_parser__Ast_utils.cmi"} 23 | "_build/install/default/lib/flow_parser/flow_parser__Ast_utils.cmt" {"flow_parser__Ast_utils.cmt"} 24 | "_build/install/default/lib/flow_parser/flow_parser__Ast_utils.cmti" {"flow_parser__Ast_utils.cmti"} 25 | "_build/install/default/lib/flow_parser/flow_parser__Ast_utils.cmx" {"flow_parser__Ast_utils.cmx"} 26 | "_build/install/default/lib/flow_parser/flow_parser__Declaration_parser.cmi" {"flow_parser__Declaration_parser.cmi"} 27 | "_build/install/default/lib/flow_parser/flow_parser__Declaration_parser.cmt" {"flow_parser__Declaration_parser.cmt"} 28 | "_build/install/default/lib/flow_parser/flow_parser__Declaration_parser.cmx" {"flow_parser__Declaration_parser.cmx"} 29 | "_build/install/default/lib/flow_parser/flow_parser__Estree_translator.cmi" {"flow_parser__Estree_translator.cmi"} 30 | "_build/install/default/lib/flow_parser/flow_parser__Estree_translator.cmt" {"flow_parser__Estree_translator.cmt"} 31 | "_build/install/default/lib/flow_parser/flow_parser__Estree_translator.cmx" {"flow_parser__Estree_translator.cmx"} 32 | "_build/install/default/lib/flow_parser/flow_parser__Expression_parser.cmi" {"flow_parser__Expression_parser.cmi"} 33 | "_build/install/default/lib/flow_parser/flow_parser__Expression_parser.cmt" {"flow_parser__Expression_parser.cmt"} 34 | "_build/install/default/lib/flow_parser/flow_parser__Expression_parser.cmx" {"flow_parser__Expression_parser.cmx"} 35 | "_build/install/default/lib/flow_parser/flow_parser__File_key.cmi" {"flow_parser__File_key.cmi"} 36 | "_build/install/default/lib/flow_parser/flow_parser__File_key.cmt" {"flow_parser__File_key.cmt"} 37 | "_build/install/default/lib/flow_parser/flow_parser__File_key.cmx" {"flow_parser__File_key.cmx"} 38 | "_build/install/default/lib/flow_parser/flow_parser__Jsx_parser.cmi" {"flow_parser__Jsx_parser.cmi"} 39 | "_build/install/default/lib/flow_parser/flow_parser__Jsx_parser.cmt" {"flow_parser__Jsx_parser.cmt"} 40 | "_build/install/default/lib/flow_parser/flow_parser__Jsx_parser.cmx" {"flow_parser__Jsx_parser.cmx"} 41 | "_build/install/default/lib/flow_parser/flow_parser__Lex_env.cmi" {"flow_parser__Lex_env.cmi"} 42 | "_build/install/default/lib/flow_parser/flow_parser__Lex_env.cmt" {"flow_parser__Lex_env.cmt"} 43 | "_build/install/default/lib/flow_parser/flow_parser__Lex_env.cmx" {"flow_parser__Lex_env.cmx"} 44 | "_build/install/default/lib/flow_parser/flow_parser__Lex_result.cmi" {"flow_parser__Lex_result.cmi"} 45 | "_build/install/default/lib/flow_parser/flow_parser__Lex_result.cmt" {"flow_parser__Lex_result.cmt"} 46 | "_build/install/default/lib/flow_parser/flow_parser__Lex_result.cmx" {"flow_parser__Lex_result.cmx"} 47 | "_build/install/default/lib/flow_parser/flow_parser__Lexer.cmi" {"flow_parser__Lexer.cmi"} 48 | "_build/install/default/lib/flow_parser/flow_parser__Lexer.cmt" {"flow_parser__Lexer.cmt"} 49 | "_build/install/default/lib/flow_parser/flow_parser__Lexer.cmx" {"flow_parser__Lexer.cmx"} 50 | "_build/install/default/lib/flow_parser/flow_parser__Libflowparser.cmi" {"flow_parser__Libflowparser.cmi"} 51 | "_build/install/default/lib/flow_parser/flow_parser__Libflowparser.cmt" {"flow_parser__Libflowparser.cmt"} 52 | "_build/install/default/lib/flow_parser/flow_parser__Libflowparser.cmx" {"flow_parser__Libflowparser.cmx"} 53 | "_build/install/default/lib/flow_parser/flow_parser__Loc.cmi" {"flow_parser__Loc.cmi"} 54 | "_build/install/default/lib/flow_parser/flow_parser__Loc.cmt" {"flow_parser__Loc.cmt"} 55 | "_build/install/default/lib/flow_parser/flow_parser__Loc.cmti" {"flow_parser__Loc.cmti"} 56 | "_build/install/default/lib/flow_parser/flow_parser__Loc.cmx" {"flow_parser__Loc.cmx"} 57 | "_build/install/default/lib/flow_parser/flow_parser__Object_parser.cmi" {"flow_parser__Object_parser.cmi"} 58 | "_build/install/default/lib/flow_parser/flow_parser__Object_parser.cmt" {"flow_parser__Object_parser.cmt"} 59 | "_build/install/default/lib/flow_parser/flow_parser__Object_parser.cmx" {"flow_parser__Object_parser.cmx"} 60 | "_build/install/default/lib/flow_parser/flow_parser__Parse_error.cmi" {"flow_parser__Parse_error.cmi"} 61 | "_build/install/default/lib/flow_parser/flow_parser__Parse_error.cmt" {"flow_parser__Parse_error.cmt"} 62 | "_build/install/default/lib/flow_parser/flow_parser__Parse_error.cmx" {"flow_parser__Parse_error.cmx"} 63 | "_build/install/default/lib/flow_parser/flow_parser__Parser_common.cmi" {"flow_parser__Parser_common.cmi"} 64 | "_build/install/default/lib/flow_parser/flow_parser__Parser_common.cmt" {"flow_parser__Parser_common.cmt"} 65 | "_build/install/default/lib/flow_parser/flow_parser__Parser_common.cmx" {"flow_parser__Parser_common.cmx"} 66 | "_build/install/default/lib/flow_parser/flow_parser__Parser_env.cmi" {"flow_parser__Parser_env.cmi"} 67 | "_build/install/default/lib/flow_parser/flow_parser__Parser_env.cmt" {"flow_parser__Parser_env.cmt"} 68 | "_build/install/default/lib/flow_parser/flow_parser__Parser_env.cmti" {"flow_parser__Parser_env.cmti"} 69 | "_build/install/default/lib/flow_parser/flow_parser__Parser_env.cmx" {"flow_parser__Parser_env.cmx"} 70 | "_build/install/default/lib/flow_parser/flow_parser__Parser_flow.cmi" {"flow_parser__Parser_flow.cmi"} 71 | "_build/install/default/lib/flow_parser/flow_parser__Parser_flow.cmt" {"flow_parser__Parser_flow.cmt"} 72 | "_build/install/default/lib/flow_parser/flow_parser__Parser_flow.cmx" {"flow_parser__Parser_flow.cmx"} 73 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_cover.cmi" {"flow_parser__Pattern_cover.cmi"} 74 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_cover.cmt" {"flow_parser__Pattern_cover.cmt"} 75 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_cover.cmx" {"flow_parser__Pattern_cover.cmx"} 76 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_parser.cmi" {"flow_parser__Pattern_parser.cmi"} 77 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_parser.cmt" {"flow_parser__Pattern_parser.cmt"} 78 | "_build/install/default/lib/flow_parser/flow_parser__Pattern_parser.cmx" {"flow_parser__Pattern_parser.cmx"} 79 | "_build/install/default/lib/flow_parser/flow_parser__Statement_parser.cmi" {"flow_parser__Statement_parser.cmi"} 80 | "_build/install/default/lib/flow_parser/flow_parser__Statement_parser.cmt" {"flow_parser__Statement_parser.cmt"} 81 | "_build/install/default/lib/flow_parser/flow_parser__Statement_parser.cmx" {"flow_parser__Statement_parser.cmx"} 82 | "_build/install/default/lib/flow_parser/flow_parser__Token.cmi" {"flow_parser__Token.cmi"} 83 | "_build/install/default/lib/flow_parser/flow_parser__Token.cmt" {"flow_parser__Token.cmt"} 84 | "_build/install/default/lib/flow_parser/flow_parser__Token.cmx" {"flow_parser__Token.cmx"} 85 | "_build/install/default/lib/flow_parser/flow_parser__Token_translator.cmi" {"flow_parser__Token_translator.cmi"} 86 | "_build/install/default/lib/flow_parser/flow_parser__Token_translator.cmt" {"flow_parser__Token_translator.cmt"} 87 | "_build/install/default/lib/flow_parser/flow_parser__Token_translator.cmx" {"flow_parser__Token_translator.cmx"} 88 | "_build/install/default/lib/flow_parser/flow_parser__Translator_intf.cmi" {"flow_parser__Translator_intf.cmi"} 89 | "_build/install/default/lib/flow_parser/flow_parser__Translator_intf.cmt" {"flow_parser__Translator_intf.cmt"} 90 | "_build/install/default/lib/flow_parser/flow_parser__Translator_intf.cmx" {"flow_parser__Translator_intf.cmx"} 91 | "_build/install/default/lib/flow_parser/flow_parser__Type_parser.cmi" {"flow_parser__Type_parser.cmi"} 92 | "_build/install/default/lib/flow_parser/flow_parser__Type_parser.cmt" {"flow_parser__Type_parser.cmt"} 93 | "_build/install/default/lib/flow_parser/flow_parser__Type_parser.cmx" {"flow_parser__Type_parser.cmx"} 94 | "_build/install/default/lib/flow_parser/jsx_parser.ml" {"jsx_parser.ml"} 95 | "_build/install/default/lib/flow_parser/lex_env.ml" {"lex_env.ml"} 96 | "_build/install/default/lib/flow_parser/lex_result.ml" {"lex_result.ml"} 97 | "_build/install/default/lib/flow_parser/lexer.ml" {"lexer.ml"} 98 | "_build/install/default/lib/flow_parser/libflowparser.ml" {"libflowparser.ml"} 99 | "_build/install/default/lib/flow_parser/loc.ml" {"loc.ml"} 100 | "_build/install/default/lib/flow_parser/loc.mli" {"loc.mli"} 101 | "_build/install/default/lib/flow_parser/object_parser.ml" {"object_parser.ml"} 102 | "_build/install/default/lib/flow_parser/opam" {"opam"} 103 | "_build/install/default/lib/flow_parser/parse_error.ml" {"parse_error.ml"} 104 | "_build/install/default/lib/flow_parser/parser_common.ml" {"parser_common.ml"} 105 | "_build/install/default/lib/flow_parser/parser_env.ml" {"parser_env.ml"} 106 | "_build/install/default/lib/flow_parser/parser_env.mli" {"parser_env.mli"} 107 | "_build/install/default/lib/flow_parser/parser_flow.ml" {"parser_flow.ml"} 108 | "_build/install/default/lib/flow_parser/pattern_cover.ml" {"pattern_cover.ml"} 109 | "_build/install/default/lib/flow_parser/pattern_parser.ml" {"pattern_parser.ml"} 110 | "_build/install/default/lib/flow_parser/statement_parser.ml" {"statement_parser.ml"} 111 | "_build/install/default/lib/flow_parser/token.ml" {"token.ml"} 112 | "_build/install/default/lib/flow_parser/token_translator.ml" {"token_translator.ml"} 113 | "_build/install/default/lib/flow_parser/translator_intf.ml" {"translator_intf.ml"} 114 | "_build/install/default/lib/flow_parser/type_parser.ml" {"type_parser.ml"} 115 | ] 116 | bin: [ 117 | "_build/install/default/bin/test_flow_parser.exe" {"test_flow_parser.exe"} 118 | ] 119 | doc: [ 120 | "_build/install/default/doc/flow_parser/LICENSE" 121 | "_build/install/default/doc/flow_parser/README.md" 122 | ] 123 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/token.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | type t = 9 | | T_NUMBER of { kind: number_type; raw: string } 10 | | T_STRING of (Loc.t * string * string * bool) (* loc, value, raw, octal *) 11 | | T_TEMPLATE_PART of (Loc.t * template_part * bool) (* loc, value, is_tail *) 12 | | T_IDENTIFIER of { loc: Loc.t; value: string; raw: string } 13 | | T_REGEXP of (Loc.t * string * string) (* /pattern/flags *) 14 | (* Syntax *) 15 | | T_LCURLY 16 | | T_RCURLY 17 | | T_LCURLYBAR 18 | | T_RCURLYBAR 19 | | T_LPAREN 20 | | T_RPAREN 21 | | T_LBRACKET 22 | | T_RBRACKET 23 | | T_SEMICOLON 24 | | T_COMMA 25 | | T_PERIOD 26 | | T_ARROW 27 | | T_ELLIPSIS 28 | | T_AT 29 | | T_POUND 30 | (* Keywords *) 31 | | T_FUNCTION 32 | | T_IF 33 | | T_IN 34 | | T_INSTANCEOF 35 | | T_RETURN 36 | | T_SWITCH 37 | | T_THIS 38 | | T_THROW 39 | | T_TRY 40 | | T_VAR 41 | | T_WHILE 42 | | T_WITH 43 | | T_CONST 44 | | T_LET 45 | | T_NULL 46 | | T_FALSE 47 | | T_TRUE 48 | | T_BREAK 49 | | T_CASE 50 | | T_CATCH 51 | | T_CONTINUE 52 | | T_DEFAULT 53 | | T_DO 54 | | T_FINALLY 55 | | T_FOR 56 | | T_CLASS 57 | | T_EXTENDS 58 | | T_STATIC 59 | | T_ELSE 60 | | T_NEW 61 | | T_DELETE 62 | | T_TYPEOF 63 | | T_VOID 64 | | T_ENUM 65 | | T_EXPORT 66 | | T_IMPORT 67 | | T_SUPER 68 | | T_IMPLEMENTS 69 | | T_INTERFACE 70 | | T_PACKAGE 71 | | T_PRIVATE 72 | | T_PROTECTED 73 | | T_PUBLIC 74 | | T_YIELD 75 | | T_DEBUGGER 76 | | T_DECLARE 77 | | T_TYPE 78 | | T_OPAQUE 79 | | T_OF 80 | | T_ASYNC 81 | | T_AWAIT 82 | | T_CHECKS 83 | (* Operators *) 84 | | T_RSHIFT3_ASSIGN 85 | | T_RSHIFT_ASSIGN 86 | | T_LSHIFT_ASSIGN 87 | | T_BIT_XOR_ASSIGN 88 | | T_BIT_OR_ASSIGN 89 | | T_BIT_AND_ASSIGN 90 | | T_MOD_ASSIGN 91 | | T_DIV_ASSIGN 92 | | T_MULT_ASSIGN 93 | | T_EXP_ASSIGN 94 | | T_MINUS_ASSIGN 95 | | T_PLUS_ASSIGN 96 | | T_ASSIGN 97 | | T_PLING_PERIOD 98 | | T_PLING 99 | | T_COLON 100 | | T_OR 101 | | T_AND 102 | | T_BIT_OR 103 | | T_BIT_XOR 104 | | T_BIT_AND 105 | | T_EQUAL 106 | | T_NOT_EQUAL 107 | | T_STRICT_EQUAL 108 | | T_STRICT_NOT_EQUAL 109 | | T_LESS_THAN_EQUAL 110 | | T_GREATER_THAN_EQUAL 111 | | T_LESS_THAN 112 | | T_GREATER_THAN 113 | | T_LSHIFT 114 | | T_RSHIFT 115 | | T_RSHIFT3 116 | | T_PLUS 117 | | T_MINUS 118 | | T_DIV 119 | | T_MULT 120 | | T_EXP 121 | | T_MOD 122 | | T_NOT 123 | | T_BIT_NOT 124 | | T_INCR 125 | | T_DECR 126 | (* Extra tokens *) 127 | | T_ERROR of string 128 | | T_EOF 129 | (* JSX *) 130 | | T_JSX_IDENTIFIER of { raw: string } 131 | | T_JSX_TEXT of (Loc.t * string * string) (* loc, value, raw *) 132 | (* Type primitives *) 133 | | T_ANY_TYPE 134 | | T_MIXED_TYPE 135 | | T_EMPTY_TYPE 136 | | T_BOOLEAN_TYPE of bool_or_boolean 137 | | T_NUMBER_TYPE 138 | | T_NUMBER_SINGLETON_TYPE of { kind: number_type; value: float; raw: string } 139 | | T_STRING_TYPE 140 | | T_VOID_TYPE 141 | 142 | (* `bool` and `boolean` are equivalent annotations, but we need to track 143 | which one was used for when it might be an identifier, as in 144 | `(bool: boolean) => void`. It's lexed as two T_BOOLEAN_TYPEs, then the 145 | first one is converted into an identifier. *) 146 | and bool_or_boolean = 147 | | BOOL 148 | | BOOLEAN 149 | 150 | and number_type = 151 | | BINARY 152 | | LEGACY_OCTAL 153 | | OCTAL 154 | | NORMAL 155 | 156 | and template_part = { 157 | cooked: string; (* string after processing special chars *) 158 | raw: string; (* string as specified in source *) 159 | literal: string; (* same as raw, plus characters like ` and ${ *) 160 | } 161 | 162 | (*****************************************************************************) 163 | (* Pretty printer (pretty?) *) 164 | (*****************************************************************************) 165 | let token_to_string = function 166 | | T_NUMBER _ -> "T_NUMBER" 167 | | T_STRING _ -> "T_STRING" 168 | | T_TEMPLATE_PART _ -> "T_TEMPLATE_PART" 169 | | T_IDENTIFIER _ -> "T_IDENTIFIER" 170 | | T_REGEXP _ -> "T_REGEXP" 171 | | T_FUNCTION -> "T_FUNCTION" 172 | | T_IF -> "T_IF" 173 | | T_IN -> "T_IN" 174 | | T_INSTANCEOF -> "T_INSTANCEOF" 175 | | T_RETURN -> "T_RETURN" 176 | | T_SWITCH -> "T_SWITCH" 177 | | T_THIS -> "T_THIS" 178 | | T_THROW -> "T_THROW" 179 | | T_TRY -> "T_TRY" 180 | | T_VAR -> "T_VAR" 181 | | T_WHILE -> "T_WHILE" 182 | | T_WITH -> "T_WITH" 183 | | T_CONST -> "T_CONST" 184 | | T_LET -> "T_LET" 185 | | T_NULL -> "T_NULL" 186 | | T_FALSE -> "T_FALSE" 187 | | T_TRUE -> "T_TRUE" 188 | | T_BREAK -> "T_BREAK" 189 | | T_CASE -> "T_CASE" 190 | | T_CATCH -> "T_CATCH" 191 | | T_CONTINUE -> "T_CONTINUE" 192 | | T_DEFAULT -> "T_DEFAULT" 193 | | T_DO -> "T_DO" 194 | | T_FINALLY -> "T_FINALLY" 195 | | T_FOR -> "T_FOR" 196 | | T_CLASS -> "T_CLASS" 197 | | T_EXTENDS -> "T_EXTENDS" 198 | | T_STATIC -> "T_STATIC" 199 | | T_ELSE -> "T_ELSE" 200 | | T_NEW -> "T_NEW" 201 | | T_DELETE -> "T_DELETE" 202 | | T_TYPEOF -> "T_TYPEOF" 203 | | T_VOID -> "T_VOID" 204 | | T_ENUM -> "T_ENUM" 205 | | T_EXPORT -> "T_EXPORT" 206 | | T_IMPORT -> "T_IMPORT" 207 | | T_SUPER -> "T_SUPER" 208 | | T_IMPLEMENTS -> "T_IMPLEMENTS" 209 | | T_INTERFACE -> "T_INTERFACE" 210 | | T_PACKAGE -> "T_PACKAGE" 211 | | T_PRIVATE -> "T_PRIVATE" 212 | | T_PROTECTED -> "T_PROTECTED" 213 | | T_PUBLIC -> "T_PUBLIC" 214 | | T_YIELD -> "T_YIELD" 215 | | T_DEBUGGER -> "T_DEBUGGER" 216 | | T_DECLARE -> "T_DECLARE" 217 | | T_TYPE -> "T_TYPE" 218 | | T_OPAQUE -> "T_OPAQUE" 219 | | T_OF -> "T_OF" 220 | | T_ASYNC -> "T_ASYNC" 221 | | T_AWAIT -> "T_AWAIT" 222 | | T_CHECKS -> "T_CHECKS" 223 | | T_LCURLY -> "T_LCURLY" 224 | | T_RCURLY -> "T_RCURLY" 225 | | T_LCURLYBAR -> "T_LCURLYBAR" 226 | | T_RCURLYBAR -> "T_RCURLYBAR" 227 | | T_LPAREN -> "T_LPAREN" 228 | | T_RPAREN -> "T_RPAREN" 229 | | T_LBRACKET -> "T_LBRACKET" 230 | | T_RBRACKET -> "T_RBRACKET" 231 | | T_SEMICOLON -> "T_SEMICOLON" 232 | | T_COMMA -> "T_COMMA" 233 | | T_PERIOD -> "T_PERIOD" 234 | | T_ARROW -> "T_ARROW" 235 | | T_ELLIPSIS -> "T_ELLIPSIS" 236 | | T_AT -> "T_AT" 237 | | T_POUND -> "T_POUND" 238 | | T_RSHIFT3_ASSIGN -> "T_RSHIFT3_ASSIGN" 239 | | T_RSHIFT_ASSIGN -> "T_RSHIFT_ASSIGN" 240 | | T_LSHIFT_ASSIGN -> "T_LSHIFT_ASSIGN" 241 | | T_BIT_XOR_ASSIGN -> "T_BIT_XOR_ASSIGN" 242 | | T_BIT_OR_ASSIGN -> "T_BIT_OR_ASSIGN" 243 | | T_BIT_AND_ASSIGN -> "T_BIT_AND_ASSIGN" 244 | | T_MOD_ASSIGN -> "T_MOD_ASSIGN" 245 | | T_DIV_ASSIGN -> "T_DIV_ASSIGN" 246 | | T_MULT_ASSIGN -> "T_MULT_ASSIGN" 247 | | T_EXP_ASSIGN -> "T_EXP_ASSIGN" 248 | | T_MINUS_ASSIGN -> "T_MINUS_ASSIGN" 249 | | T_PLUS_ASSIGN -> "T_PLUS_ASSIGN" 250 | | T_ASSIGN -> "T_ASSIGN" 251 | | T_PLING_PERIOD -> "T_PLING_PERIOD" 252 | | T_PLING -> "T_PLING" 253 | | T_COLON -> "T_COLON" 254 | | T_OR -> "T_OR" 255 | | T_AND -> "T_AND" 256 | | T_BIT_OR -> "T_BIT_OR" 257 | | T_BIT_XOR -> "T_BIT_XOR" 258 | | T_BIT_AND -> "T_BIT_AND" 259 | | T_EQUAL -> "T_EQUAL" 260 | | T_NOT_EQUAL -> "T_NOT_EQUAL" 261 | | T_STRICT_EQUAL -> "T_STRICT_EQUAL" 262 | | T_STRICT_NOT_EQUAL -> "T_STRICT_NOT_EQUAL" 263 | | T_LESS_THAN_EQUAL -> "T_LESS_THAN_EQUAL" 264 | | T_GREATER_THAN_EQUAL -> "T_GREATER_THAN_EQUAL" 265 | | T_LESS_THAN -> "T_LESS_THAN" 266 | | T_GREATER_THAN -> "T_GREATER_THAN" 267 | | T_LSHIFT -> "T_LSHIFT" 268 | | T_RSHIFT -> "T_RSHIFT" 269 | | T_RSHIFT3 -> "T_RSHIFT3" 270 | | T_PLUS -> "T_PLUS" 271 | | T_MINUS -> "T_MINUS" 272 | | T_DIV -> "T_DIV" 273 | | T_MULT -> "T_MULT" 274 | | T_EXP -> "T_EXP" 275 | | T_MOD -> "T_MOD" 276 | | T_NOT -> "T_NOT" 277 | | T_BIT_NOT -> "T_BIT_NOT" 278 | | T_INCR -> "T_INCR" 279 | | T_DECR -> "T_DECR" 280 | (* Extra tokens *) 281 | | T_ERROR _ -> "T_ERROR" 282 | | T_EOF -> "T_EOF" 283 | | T_JSX_IDENTIFIER _ -> "T_JSX_IDENTIFIER" 284 | | T_JSX_TEXT _ -> "T_JSX_TEXT" 285 | (* Type primitives *) 286 | | T_ANY_TYPE -> "T_ANY_TYPE" 287 | | T_MIXED_TYPE -> "T_MIXED_TYPE" 288 | | T_EMPTY_TYPE -> "T_EMPTY_TYPE" 289 | | T_BOOLEAN_TYPE _ -> "T_BOOLEAN_TYPE" 290 | | T_NUMBER_TYPE -> "T_NUMBER_TYPE" 291 | | T_NUMBER_SINGLETON_TYPE _ -> "T_NUMBER_SINGLETON_TYPE" 292 | | T_STRING_TYPE -> "T_STRING_TYPE" 293 | | T_VOID_TYPE -> "T_VOID_TYPE" 294 | 295 | let value_of_token = function 296 | | T_NUMBER { raw; _ } -> raw 297 | | T_STRING (_, _, raw, _) -> raw 298 | | T_TEMPLATE_PART (_, { literal; _ }, _) -> literal 299 | | T_IDENTIFIER { raw; _ } -> raw 300 | | T_REGEXP (_, pattern, flags) -> "/" ^ pattern ^ "/" ^ flags 301 | | T_LCURLY -> "{" 302 | | T_RCURLY -> "}" 303 | | T_LCURLYBAR -> "{|" 304 | | T_RCURLYBAR -> "|}" 305 | | T_LPAREN -> "(" 306 | | T_RPAREN -> ")" 307 | | T_LBRACKET -> "[" 308 | | T_RBRACKET -> "]" 309 | | T_SEMICOLON -> ";" 310 | | T_COMMA -> "," 311 | | T_PERIOD -> "." 312 | | T_ARROW -> "=>" 313 | | T_ELLIPSIS -> "..." 314 | | T_AT -> "@" 315 | | T_POUND -> "#" 316 | | T_FUNCTION -> "function" 317 | | T_IF -> "if" 318 | | T_IN -> "in" 319 | | T_INSTANCEOF -> "instanceof" 320 | | T_RETURN -> "return" 321 | | T_SWITCH -> "switch" 322 | | T_THIS -> "this" 323 | | T_THROW -> "throw" 324 | | T_TRY -> "try" 325 | | T_VAR -> "var" 326 | | T_WHILE -> "while" 327 | | T_WITH -> "with" 328 | | T_CONST -> "const" 329 | | T_LET -> "let" 330 | | T_NULL -> "null" 331 | | T_FALSE -> "false" 332 | | T_TRUE -> "true" 333 | | T_BREAK -> "break" 334 | | T_CASE -> "case" 335 | | T_CATCH -> "catch" 336 | | T_CONTINUE -> "continue" 337 | | T_DEFAULT -> "default" 338 | | T_DO -> "do" 339 | | T_FINALLY -> "finally" 340 | | T_FOR -> "for" 341 | | T_CLASS -> "class" 342 | | T_EXTENDS -> "extends" 343 | | T_STATIC -> "static" 344 | | T_ELSE -> "else" 345 | | T_NEW -> "new" 346 | | T_DELETE -> "delete" 347 | | T_TYPEOF -> "typeof" 348 | | T_VOID -> "void" 349 | | T_ENUM -> "enum" 350 | | T_EXPORT -> "export" 351 | | T_IMPORT -> "import" 352 | | T_SUPER -> "super" 353 | | T_IMPLEMENTS -> "implements" 354 | | T_INTERFACE -> "interface" 355 | | T_PACKAGE -> "package" 356 | | T_PRIVATE -> "private" 357 | | T_PROTECTED -> "protected" 358 | | T_PUBLIC -> "public" 359 | | T_YIELD -> "yield" 360 | | T_DEBUGGER -> "debugger" 361 | | T_DECLARE -> "declare" 362 | | T_TYPE -> "type" 363 | | T_OPAQUE -> "opaque" 364 | | T_OF -> "of" 365 | | T_ASYNC -> "async" 366 | | T_AWAIT -> "await" 367 | | T_CHECKS -> "%checks" 368 | | T_RSHIFT3_ASSIGN -> ">>>=" 369 | | T_RSHIFT_ASSIGN -> ">>=" 370 | | T_LSHIFT_ASSIGN -> "<<=" 371 | | T_BIT_XOR_ASSIGN -> "^=" 372 | | T_BIT_OR_ASSIGN -> "|=" 373 | | T_BIT_AND_ASSIGN -> "&=" 374 | | T_MOD_ASSIGN -> "%=" 375 | | T_DIV_ASSIGN -> "/=" 376 | | T_MULT_ASSIGN -> "*=" 377 | | T_EXP_ASSIGN -> "**=" 378 | | T_MINUS_ASSIGN -> "-=" 379 | | T_PLUS_ASSIGN -> "+=" 380 | | T_ASSIGN -> "=" 381 | | T_PLING_PERIOD -> "?." 382 | | T_PLING -> "?" 383 | | T_COLON -> ":" 384 | | T_OR -> "||" 385 | | T_AND -> "&&" 386 | | T_BIT_OR -> "|" 387 | | T_BIT_XOR -> "^" 388 | | T_BIT_AND -> "&" 389 | | T_EQUAL -> "==" 390 | | T_NOT_EQUAL -> "!=" 391 | | T_STRICT_EQUAL -> "===" 392 | | T_STRICT_NOT_EQUAL -> "!==" 393 | | T_LESS_THAN_EQUAL -> "<=" 394 | | T_GREATER_THAN_EQUAL -> ">=" 395 | | T_LESS_THAN -> "<" 396 | | T_GREATER_THAN -> ">" 397 | | T_LSHIFT -> "<<" 398 | | T_RSHIFT -> ">>" 399 | | T_RSHIFT3 -> ">>>" 400 | | T_PLUS -> "+" 401 | | T_MINUS -> "-" 402 | | T_DIV -> "/" 403 | | T_MULT -> "*" 404 | | T_EXP -> "**" 405 | | T_MOD -> "%" 406 | | T_NOT -> "!" 407 | | T_BIT_NOT -> "~" 408 | | T_INCR -> "++" 409 | | T_DECR -> "--" 410 | | T_ERROR raw -> raw 411 | | T_EOF -> "" 412 | | T_JSX_IDENTIFIER { raw } -> raw 413 | | T_JSX_TEXT (_, _, raw) -> raw 414 | | T_ANY_TYPE -> "any" 415 | | T_MIXED_TYPE -> "mixed" 416 | | T_EMPTY_TYPE -> "empty" 417 | | T_BOOLEAN_TYPE kind -> begin match kind with BOOL -> "bool" | BOOLEAN -> "boolean" end 418 | | T_NUMBER_TYPE -> "number" 419 | | T_NUMBER_SINGLETON_TYPE { raw; _ } -> raw 420 | | T_STRING_TYPE -> "string" 421 | | T_VOID_TYPE -> "void" 422 | -------------------------------------------------------------------------------- /InfraredParser/Printer.ml: -------------------------------------------------------------------------------- 1 | open Ast 2 | open InfraredUtils 3 | module FlowAst = Flow_parser.Ast 4 | module Loc = Flow_parser.Loc 5 | module Err = Flow_parser.Parse_error 6 | 7 | let string_of_type (t : string) : string = 8 | Printf.sprintf "[%s] " 9 | (Chalk.green t) 10 | 11 | let get_type tbl key = 12 | try Hashtbl.find tbl key 13 | with _ -> Generic "unable-to-find-this-type-this-is-a-bug" 14 | 15 | let rec string_of_infrared_statement ?depth:(depth=0) ?tag:(tag="") (statement: InfraredAst.statement) : string = 16 | let open InfraredAst in 17 | let string_of_type (t : string) = string_of_type (tag ^ t) in 18 | let padding = String.make depth '\t' in 19 | let (_, statement) = statement in 20 | match statement with 21 | | VariableDeclaration ((_, id), value) -> 22 | Printf.sprintf "%s%s %s <- %s" 23 | padding 24 | (string_of_type "VariableDeclaration") 25 | id 26 | (string_of_infrared_expression ~depth:depth value) 27 | | FunctionDeclaration ((_, name), params, body) -> 28 | let params_no_loc = List.map (fun (_, p) -> p) params in 29 | let params' = String.concat ", " params_no_loc in 30 | let body' = String.concat "\n" 31 | (List.map (string_of_infrared_statement ~depth:(depth + 1)) 32 | body) 33 | in 34 | Printf.sprintf "%s%s %s (%s) {\n%s\n%s}" 35 | padding 36 | (string_of_type "FunctionDeclaration") 37 | name 38 | (params') 39 | (body') 40 | padding 41 | | Return expr -> 42 | Printf.sprintf "%s%sreturn %s" 43 | padding 44 | (string_of_type "Return") 45 | (string_of_infrared_expression ~depth:depth expr) 46 | | Expression expr -> 47 | Printf.sprintf "%s%s%s" 48 | padding 49 | (string_of_type "Expression") 50 | (string_of_infrared_expression ~depth:depth expr) 51 | | If (expr, s1, s2) -> 52 | Printf.sprintf "%s%sif (%s)\n%s\n%s" 53 | padding 54 | (string_of_type "IfStatement") 55 | (string_of_infrared_expression ~depth:(depth + 1) expr) 56 | (string_of_infrared_statement ~depth:(depth + 1) ~tag:("Then") s1) 57 | (string_of_infrared_statement ~depth:(depth + 1) ~tag:("Else") s2) 58 | | Block statements -> 59 | let statement_strs = List.map (string_of_infrared_statement ~depth:(depth + 1)) statements in 60 | Printf.sprintf "%s%s{\n%s\n%s}" 61 | padding 62 | (string_of_type "Block") 63 | (String.concat "\n" statement_strs) 64 | padding 65 | 66 | and string_of_infrared_expression ?depth:(depth=0) (expression : InfraredAst.expression) : string = 67 | let open InfraredAst in 68 | let padding = String.make depth '\t' in 69 | let (_, expression) = expression in 70 | match expression with 71 | | Variable (_, id) -> id 72 | | String s -> "\"" ^ s ^ "\"" 73 | | Number n -> string_of_int n 74 | | Boolean b -> string_of_bool b 75 | | Null -> "null" 76 | | Undefined -> "undefined" 77 | | BinaryOperation (binop, left, right) -> 78 | Printf.sprintf "%s %s %s" 79 | (string_of_infrared_expression ~depth:depth left) 80 | (string_of_infrared_binop binop) 81 | (string_of_infrared_expression ~depth:depth right) 82 | | Assignment ((_, id), expr) -> 83 | Printf.sprintf "%s = %s" 84 | (id) 85 | (string_of_infrared_expression ~depth:depth expr) 86 | | Object pairs -> 87 | let pairs_strs = List.map (fun pair -> 88 | let ((_, key), value) = pair in 89 | let value_str = string_of_infrared_expression ~depth:(depth + 1) value in 90 | Printf.sprintf "\n\t%s%s: %s" 91 | padding 92 | key 93 | value_str 94 | ) pairs 95 | in 96 | let formatted_pairs = String.concat "," pairs_strs in 97 | Printf.sprintf "{%s\n%s}" 98 | formatted_pairs 99 | padding 100 | | Access (e1, e2) -> 101 | Printf.sprintf "(%s%s)" 102 | (string_of_infrared_expression ~depth:depth e1) 103 | (string_of_infrared_property e2) 104 | | Call (callee, args) -> 105 | let pp_args = List.map (string_of_infrared_expression ~depth:depth) args in 106 | let pp_args_str = String.concat ", " pp_args in 107 | Printf.sprintf "%s(%s)" 108 | (string_of_infrared_expression ~depth:depth callee) 109 | pp_args_str 110 | | _ -> string_of_type "#" 111 | 112 | and string_of_infrared_property (prop : InfraredAst.property) : string = 113 | let open InfraredAst in 114 | match prop with 115 | | PropertyExpression expr -> "[" ^ (string_of_infrared_expression expr) ^ "]" 116 | | PropertyIdentifier (_, id) -> "." ^ id 117 | 118 | and string_of_infrared_binop (binop : InfraredAst.binop) : string = 119 | let open InfraredAst in 120 | match binop with 121 | | Plus -> "+" 122 | | Minus -> "-" 123 | | Multiply -> "*" 124 | | Divide -> "/" 125 | | Exponent -> "**" 126 | | Modulo -> "%" 127 | | LeftShift -> ">>" 128 | | RightShift -> "<<" 129 | | BitOr -> "|" 130 | | BitXor -> "^" 131 | | BitAnd -> "&" 132 | | And -> "&&" 133 | | Or -> "||" 134 | | In -> "in" 135 | | InstanceOf -> "instanceof" 136 | | Compare cmp -> 137 | ( 138 | match cmp with 139 | | Equal -> "==" 140 | | NotEqual -> "!=" 141 | | GreaterThan -> ">" 142 | | LessThan -> "<" 143 | ) 144 | 145 | let rec string_of_primative ?depth:(depth=0) (prim : primative_data_type) : string = 146 | let padding = String.make depth '\t' in 147 | match prim with 148 | | Null -> "Null" 149 | | Undefined -> "Undefined" 150 | | String -> "String" 151 | | Boolean -> "Boolean" 152 | | Number -> "Number" 153 | | Object pairs -> 154 | let pp_pairs = List.map (fun pair -> 155 | let (key, d_type) = pair in 156 | Printf.sprintf "\n%s\t%s: %s" 157 | padding 158 | key 159 | (string_of_data_type ~depth:(depth + 1) d_type) 160 | ) pairs 161 | in 162 | Printf.sprintf "Object {%s\n%s}" 163 | (String.concat "; " pp_pairs) 164 | padding 165 | | Array _ -> "Array" 166 | | Function (params, ret) -> 167 | let pp_params = List.map (string_of_data_type ~depth:depth) params in 168 | let pp_params_str = String.concat " → " pp_params in 169 | let pp_ret = string_of_data_type ~depth:depth ret in 170 | Printf.sprintf "(%s) → %s" 171 | pp_params_str 172 | pp_ret 173 | 174 | and string_of_data_type ?depth:(depth=0) (d_type : data_type) : string = 175 | match d_type with 176 | | Generic tag -> "'" ^ tag 177 | | Defer _expr -> "Defer" 178 | | Exec (callee_d_type, args_d_types) -> 179 | let pp_args_d_types = List.map (string_of_data_type ~depth:depth) args_d_types in 180 | let pp_args_d_types_str = String.concat ", " pp_args_d_types in 181 | Printf.sprintf "App(%s, (%s))" 182 | (string_of_data_type ~depth:depth callee_d_type) 183 | (pp_args_d_types_str) 184 | | Primative prim -> string_of_primative ~depth:depth prim 185 | | Reduction d_types -> 186 | let d_types_str = List.map (string_of_data_type ~depth:depth) d_types in 187 | let str = String.concat ", " d_types_str in 188 | Printf.sprintf "Reduce(%s)" 189 | str 190 | | Union d_types -> 191 | let d_types_str = List.map (string_of_data_type ~depth:depth) d_types in 192 | let str = String.concat " ∨ " d_types_str in 193 | Printf.sprintf "Union(%s)" 194 | str 195 | | Drill (d_type, prop) -> 196 | Printf.sprintf "Access(%s, %s)" 197 | (string_of_data_type ~depth:depth d_type) 198 | (string_of_infrared_property prop) 199 | | Unknown -> Chalk.red "Unknown" 200 | 201 | let pp_string_of_data_type ?depth:(depth=0) (d_type : data_type) : string = 202 | let d_type_str = string_of_data_type ~depth:depth d_type in 203 | let str = "⊢ " ^ d_type_str in 204 | str |> Chalk.white |> Chalk.bold 205 | 206 | let rec string_of_typed_infrared_statement ?depth:(depth=0) ?tag:(tag="") (statement: TypedInfraredAst.statement) (env : environment) : string = 207 | let open TypedInfraredAst in 208 | let string_of_type (t : string) = string_of_type (tag ^ t) in 209 | let padding = String.make depth '\t' in 210 | let (_, statement) = statement in 211 | match statement with 212 | | VariableDeclaration ((_, id), typed_value) -> 213 | let (d_type, value) = typed_value in 214 | Printf.sprintf "%s%s %s <- %s %s" 215 | padding 216 | (string_of_type "VariableDeclaration") 217 | id 218 | (string_of_infrared_expression ~depth:depth value) 219 | (pp_string_of_data_type ~depth:depth d_type) 220 | | FunctionDeclaration ((_, name), params, body) -> 221 | let typed_params = List.map (fun (_, param) -> 222 | let d_type = get_type env param in 223 | (d_type, param) 224 | ) params 225 | in 226 | let formatted_typed_params = List.map (fun typed_param -> 227 | let (d_type, param) = typed_param in 228 | Printf.sprintf "%s %s" 229 | param 230 | (pp_string_of_data_type ~depth:depth d_type) 231 | ) typed_params 232 | in 233 | let params' = String.concat ", " formatted_typed_params in 234 | let body' = String.concat "\n" 235 | (List.map (fun s -> string_of_typed_infrared_statement ~depth:(depth + 1) s env) 236 | body) 237 | in 238 | let return_d_type = get_type env name in 239 | Printf.sprintf "%s%s %s (%s) %s {\n%s\n%s}" 240 | padding 241 | (string_of_type "FunctionDeclaration") 242 | name 243 | (params') 244 | (pp_string_of_data_type ~depth:depth return_d_type) 245 | (body') 246 | padding 247 | | Return expr -> 248 | let (d_type, expr) = expr in 249 | Printf.sprintf "%s%sreturn %s %s" 250 | padding 251 | (string_of_type "Return") 252 | (string_of_infrared_expression ~depth:depth expr) 253 | (pp_string_of_data_type ~depth:depth d_type) 254 | | Expression typed_expr -> 255 | let (d_type, expr) = typed_expr in 256 | Printf.sprintf "%s%s %s %s" 257 | padding 258 | (string_of_type "Expression") 259 | (string_of_infrared_expression ~depth:depth expr) 260 | (pp_string_of_data_type ~depth:depth d_type) 261 | | If (expr, s1, s2) -> 262 | let (d_type, expr) = expr in 263 | Printf.sprintf "%s%sif (%s %s)\n%s\n%s" 264 | padding 265 | (string_of_type "IfStatement") 266 | (string_of_infrared_expression ~depth:(depth + 1) expr) 267 | (pp_string_of_data_type ~depth:depth d_type) 268 | (string_of_typed_infrared_statement ~depth:(depth + 1) ~tag:("Then") s1 env) 269 | (string_of_typed_infrared_statement ~depth:(depth + 1) ~tag:("Else") s2 env) 270 | | Block statements -> 271 | let statement_strs = List.map 272 | (fun s -> string_of_typed_infrared_statement ~depth:(depth + 1) s env) statements in 273 | Printf.sprintf "%s%s{\n%s\n%s}" 274 | padding 275 | (string_of_type "Block") 276 | (String.concat "\n" statement_strs) 277 | padding 278 | 279 | let string_of_infrared_ast (statements : InfraredAst.statement list) : string = 280 | let statement_strings = List.map string_of_infrared_statement statements in 281 | let joined_statement_strings = String.concat "\n" statement_strings in 282 | "\n" ^ joined_statement_strings 283 | 284 | let string_of_typed_infrared_ast (statements : TypedInfraredAst.statement list) (env : environment) : string = 285 | let statement_strings = List.map (fun s -> string_of_typed_infrared_statement s env) statements in 286 | let joined_statement_strings = String.concat "\n" statement_strings in 287 | "\n" ^ joined_statement_strings 288 | 289 | let string_of_ast (ast : Loc.t FlowAst.program * (Loc.t * Err.t) list) : string = 290 | let flow_ast = FlowPrinter.string_of_ast ast in 291 | flow_ast 292 | 293 | let string_of_program (prog: program) : string = 294 | match prog with 295 | | FlowProgram (ast, errs) -> FlowPrinter.string_of_ast (ast, errs) 296 | | InfraredProgram (statements) -> string_of_infrared_ast statements 297 | | TypedInfraredProgram (statements, env) -> string_of_typed_infrared_ast statements env 298 | 299 | let string_of_title (title : string) : string = 300 | let ending_str = "<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" in 301 | let length_of_ending_str = String.length ending_str in 302 | let length_of_title = String.length title in 303 | let final_ending_str = 304 | Printf.sprintf "%s ✨" 305 | (String.sub ending_str 0 306 | (Utils.math_max 307 | (length_of_ending_str - length_of_title + 8) 0)) 308 | in 309 | Printf.sprintf "%s %s %s" 310 | (Chalk.cyan "<><>") 311 | (Chalk.bold title) 312 | (Chalk.cyan final_ending_str) 313 | 314 | let pprint_program_with_title (title : string) (program : program) : program = 315 | let title = string_of_title title in 316 | Printf.printf "%s %s\n\n" 317 | title 318 | (string_of_program program); 319 | program 320 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/jsx_parser.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | open Token 9 | open Parser_env 10 | open Ast 11 | module Error = Parse_error 12 | 13 | module JSX (Parse: Parser_common.PARSER) = struct 14 | let spread_attribute env = 15 | Eat.push_lex_mode env Lex_mode.NORMAL; 16 | let start_loc = Peek.loc env in 17 | Expect.token env T_LCURLY; 18 | Expect.token env T_ELLIPSIS; 19 | let argument = Parse.assignment env in 20 | let end_loc = Peek.loc env in 21 | Expect.token env T_RCURLY; 22 | Eat.pop_lex_mode env; 23 | Loc.btwn start_loc end_loc, JSX.SpreadAttribute.({ 24 | argument; 25 | }) 26 | 27 | let expression_container' env start_loc = 28 | let expression = if Peek.token env = T_RCURLY 29 | then 30 | let empty_loc = Loc.btwn_exclusive start_loc (Peek.loc env) in 31 | JSX.ExpressionContainer.EmptyExpression empty_loc 32 | else JSX.ExpressionContainer.Expression (Parse.expression env) in 33 | let end_loc = Peek.loc env in 34 | Expect.token env T_RCURLY; 35 | Eat.pop_lex_mode env; 36 | Loc.btwn start_loc end_loc, JSX.ExpressionContainer.({ 37 | expression; 38 | }) 39 | 40 | let expression_container env = 41 | Eat.push_lex_mode env Lex_mode.NORMAL; 42 | let start_loc = Peek.loc env in 43 | Expect.token env T_LCURLY; 44 | expression_container' env start_loc 45 | 46 | let expression_container_or_spread_child env = 47 | Eat.push_lex_mode env Lex_mode.NORMAL; 48 | let start_loc = Peek.loc env in 49 | Expect.token env T_LCURLY; 50 | match Peek.token env with 51 | | T_ELLIPSIS -> 52 | Expect.token env T_ELLIPSIS; 53 | let expr = Parse.assignment env in 54 | let end_loc = Peek.loc env in 55 | Expect.token env T_RCURLY; 56 | Eat.pop_lex_mode env; 57 | Loc.btwn start_loc end_loc, JSX.SpreadChild expr 58 | | _ -> 59 | let expression_container = expression_container' env start_loc in 60 | fst expression_container, JSX.ExpressionContainer (snd expression_container) 61 | 62 | let identifier env = 63 | let loc = Peek.loc env in 64 | let name = match Peek.token env with 65 | | T_JSX_IDENTIFIER { raw } -> raw 66 | | _ -> error_unexpected env; "" 67 | in 68 | Eat.token env; 69 | loc, JSX.Identifier.({ name; }) 70 | 71 | let name = 72 | let rec member_expression env member = 73 | match Peek.token env with 74 | | T_PERIOD -> 75 | let _object = JSX.MemberExpression.MemberExpression member in 76 | Expect.token env T_PERIOD; 77 | let property = identifier env in 78 | let loc = Loc.btwn (fst member) (fst property) in 79 | let member = loc, JSX.MemberExpression.({ 80 | _object; 81 | property; 82 | }) in 83 | member_expression env member 84 | | _ -> member 85 | 86 | in fun env -> 87 | let name = identifier env in 88 | match Peek.token env with 89 | | T_COLON -> 90 | let namespace = name in 91 | Expect.token env T_COLON; 92 | let name = identifier env in 93 | let loc = Loc.btwn (fst namespace) (fst name) in 94 | JSX.NamespacedName (loc, JSX.NamespacedName.({ 95 | namespace; 96 | name; 97 | })) 98 | | T_PERIOD -> 99 | let _object = JSX.MemberExpression.Identifier name in 100 | Expect.token env T_PERIOD; 101 | let property = identifier env in 102 | let loc = Loc.btwn (fst name) (fst property) in 103 | let member = loc, JSX.MemberExpression.({ 104 | _object; 105 | property; 106 | }) in 107 | JSX.MemberExpression (member_expression env member) 108 | | _ -> JSX.Identifier name 109 | 110 | 111 | let attribute env = 112 | let start_loc = Peek.loc env in 113 | let name = identifier env in 114 | let end_loc, name = 115 | if Peek.token env = T_COLON 116 | then begin 117 | Expect.token env T_COLON; 118 | let namespace = name in 119 | let name = identifier env in 120 | let loc = Loc.btwn (fst namespace) (fst name) in 121 | loc, JSX.Attribute.NamespacedName (loc, JSX.NamespacedName.({ 122 | namespace; 123 | name; 124 | })) 125 | end else fst name, JSX.Attribute.Identifier name in 126 | let end_loc, value = 127 | if Peek.token env = T_ASSIGN 128 | then begin 129 | Expect.token env T_ASSIGN; 130 | match Peek.token env with 131 | | T_LCURLY -> 132 | let loc, expression_container = expression_container env in 133 | begin 134 | let open JSX.ExpressionContainer in 135 | match expression_container.expression with 136 | | EmptyExpression _ -> 137 | error_at env (loc, Error.JSXAttributeValueEmptyExpression); 138 | | _ -> () 139 | end; 140 | loc, Some (JSX.Attribute.ExpressionContainer (loc, expression_container)) 141 | | T_JSX_TEXT (loc, value, raw) as token -> 142 | Expect.token env token; 143 | let value = Ast.Literal.String value in 144 | loc, Some (JSX.Attribute.Literal (loc, { Ast.Literal.value; raw;})) 145 | | _ -> 146 | error env Error.InvalidJSXAttributeValue; 147 | let loc = Peek.loc env in 148 | let raw = "" in 149 | let value = Ast.Literal.String "" in 150 | loc, Some (JSX.Attribute.Literal (loc, { Ast.Literal.value; raw;})) 151 | end else end_loc, None in 152 | Loc.btwn start_loc end_loc, JSX.Attribute.({ 153 | name; 154 | value; 155 | }) 156 | 157 | let opening_element_without_lt = 158 | let rec attributes env acc = 159 | match Peek.token env with 160 | | T_EOF 161 | | T_DIV 162 | | T_GREATER_THAN -> List.rev acc 163 | | T_LCURLY -> 164 | let attribute = JSX.Opening.SpreadAttribute (spread_attribute env) in 165 | attributes env (attribute::acc) 166 | | _ -> 167 | let attribute = JSX.Opening.Attribute (attribute env) in 168 | attributes env (attribute::acc) 169 | 170 | in fun env start_loc -> 171 | let (name, attributes, selfClosing) = match Peek.token env with 172 | | T_GREATER_THAN -> 173 | (None, [], false) 174 | | _ -> 175 | let name = Some (name env) in 176 | let attributes = attributes env [] in 177 | let selfClosing = Peek.token env = T_DIV in 178 | (name, attributes, selfClosing) in 179 | if selfClosing then Expect.token env T_DIV; 180 | let end_loc = Peek.loc env in 181 | Expect.token env T_GREATER_THAN; 182 | Eat.pop_lex_mode env; 183 | match name with 184 | | Some name -> 185 | Loc.btwn start_loc end_loc, `Element JSX.Opening.({ 186 | name; 187 | selfClosing; 188 | attributes; 189 | }) 190 | | None -> 191 | Loc.btwn start_loc end_loc, `Fragment 192 | 193 | let closing_element_without_lt env start_loc = 194 | Expect.token env T_DIV; 195 | let name = match Peek.token env with 196 | | T_GREATER_THAN -> None 197 | | _ -> Some (name env) in 198 | let end_loc = Peek.loc env in 199 | Expect.token env T_GREATER_THAN; 200 | (* We double pop to avoid going back to childmode and re-lexing the 201 | * lookahead *) 202 | Eat.double_pop_lex_mode env; 203 | match name with 204 | | Some name -> 205 | Loc.btwn start_loc end_loc, `Element JSX.Closing.({ 206 | name; 207 | }) 208 | | None -> 209 | Loc.btwn start_loc end_loc, `Fragment 210 | 211 | type element_or_closing = 212 | | Closing of Loc.t JSX.Closing.t 213 | | ClosingFragment of Loc.t 214 | | ChildElement of (Loc.t * Loc.t JSX.element) 215 | | ChildFragment of (Loc.t * Loc.t JSX.fragment) 216 | 217 | let rec child env = 218 | match Peek.token env with 219 | | T_LCURLY -> expression_container_or_spread_child env 220 | | T_JSX_TEXT (loc, value, raw) as token -> 221 | Expect.token env token; 222 | loc, JSX.Text { JSX.Text.value; raw; } 223 | | _ -> 224 | (match element_or_fragment env with 225 | | (loc, `Element element) -> loc, JSX.Element element 226 | | (loc, `Fragment fragment) -> loc, JSX.Fragment fragment) 227 | 228 | and element_without_lt = 229 | let element_or_closing env = 230 | Eat.push_lex_mode env Lex_mode.JSX_TAG; 231 | let start_loc = Peek.loc env in 232 | Expect.token env T_LESS_THAN; 233 | match Peek.token env with 234 | | T_EOF 235 | | T_DIV -> (match closing_element_without_lt env start_loc with 236 | | (loc, `Element ec) -> Closing (loc, ec) 237 | | (loc, `Fragment) -> ClosingFragment loc) 238 | | _ -> (match element_without_lt env start_loc with 239 | | (loc, `Element e) -> ChildElement (loc, e) 240 | | (loc, `Fragment f) -> ChildFragment (loc, f)) 241 | 242 | in let rec children_and_closing env acc = 243 | match Peek.token env with 244 | | T_LESS_THAN -> ( 245 | match element_or_closing env with 246 | | Closing closingElement -> 247 | List.rev acc, `Element closingElement 248 | | ClosingFragment closingFragment -> 249 | List.rev acc, `Fragment closingFragment 250 | | ChildElement element -> 251 | let element = fst element, JSX.Element (snd element) in 252 | children_and_closing env (element::acc) 253 | | ChildFragment fragment -> 254 | let fragment = fst fragment, JSX.Fragment (snd fragment) in 255 | children_and_closing env (fragment::acc)) 256 | | T_EOF -> 257 | error_unexpected env; 258 | List.rev acc, `None 259 | | _ -> 260 | children_and_closing env ((child env)::acc) 261 | 262 | in let rec normalize name = JSX.(match name with 263 | | Identifier (_, { Identifier.name }) -> name 264 | | NamespacedName (_, { NamespacedName.namespace; name; }) -> 265 | (snd namespace).Identifier.name ^ ":" ^ (snd name).Identifier.name 266 | | MemberExpression (_, { MemberExpression._object; property; }) -> 267 | let _object = match _object with 268 | | MemberExpression.Identifier (_, {Identifier.name=id; _;}) -> id 269 | | MemberExpression.MemberExpression e -> 270 | normalize (JSX.MemberExpression e) in 271 | _object ^ "." ^ (snd property).Identifier.name 272 | ) 273 | 274 | in fun env start_loc -> 275 | let openingElement = opening_element_without_lt env start_loc in 276 | let children, closingElement = 277 | let selfClosing = match snd openingElement with 278 | | `Element e -> e.JSX.Opening.selfClosing 279 | | `Fragment -> false in 280 | if selfClosing 281 | then [], `None 282 | else begin 283 | Eat.push_lex_mode env Lex_mode.JSX_CHILD; 284 | let ret = children_and_closing env [] in 285 | ret 286 | end in 287 | let end_loc = match closingElement with 288 | | `Element (loc, { JSX.Closing.name }) -> 289 | (match snd openingElement with 290 | | `Element e -> 291 | let opening_name = normalize e.JSX.Opening.name in 292 | if normalize name <> opening_name 293 | then error env (Error.ExpectedJSXClosingTag opening_name) 294 | | `Fragment -> error env (Error.ExpectedJSXClosingTag "JSX fragment")); 295 | loc 296 | | `Fragment loc -> 297 | (match snd openingElement with 298 | | `Element e -> error env (Error.ExpectedJSXClosingTag (normalize e.JSX.Opening.name)) 299 | | _ -> ()); 300 | loc 301 | | _ -> fst openingElement in 302 | match snd openingElement with 303 | | `Element e -> 304 | Loc.btwn (fst openingElement) end_loc, `Element JSX.({ 305 | openingElement = (fst openingElement, e); 306 | closingElement = (match closingElement with 307 | | `Element e -> Some e 308 | | _ -> None); 309 | children; 310 | }) 311 | | `Fragment -> 312 | Loc.btwn (fst openingElement) end_loc, `Fragment JSX.({ 313 | frag_openingElement = fst openingElement; 314 | frag_closingElement = (match closingElement with 315 | | `Fragment loc -> Some loc 316 | | _ -> None); 317 | frag_children = children; 318 | }) 319 | 320 | and element_or_fragment env = 321 | let start_loc = Peek.loc env in 322 | Eat.push_lex_mode env Lex_mode.JSX_TAG; 323 | Expect.token env T_LESS_THAN; 324 | element_without_lt env start_loc 325 | end 326 | -------------------------------------------------------------------------------- /InfraredParser/flow_parser/lib/declaration_parser.ml: -------------------------------------------------------------------------------- 1 | (** 2 | * Copyright (c) 2013-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | *) 7 | 8 | open Token 9 | open Parser_common 10 | open Parser_env 11 | open Ast 12 | module Error = Parse_error 13 | module SSet = Set.Make(String) 14 | 15 | module type DECLARATION = sig 16 | val async: env -> bool 17 | val generator: env -> bool 18 | val variance: env -> bool -> bool -> Loc.t Variance.t option 19 | val function_params: await:bool -> yield:bool -> env -> Loc.t Ast.Function.Params.t 20 | val function_body: env -> async:bool -> generator:bool -> Loc.t * Loc.t Function.body * bool 21 | val is_simple_function_params: Loc.t Ast.Function.Params.t -> bool 22 | val strict_post_check: env -> strict:bool -> simple:bool -> Loc.t Identifier.t option -> Loc.t Ast.Function.Params.t -> unit 23 | val concise_function_body: env -> async:bool -> generator:bool -> Loc.t Function.body * bool 24 | val variable: env -> Loc.t Statement.t * (Loc.t * Error.t) list 25 | val variable_declaration_list: env -> Loc.t Statement.VariableDeclaration.Declarator.t list * (Loc.t * Error.t) list 26 | val let_: env -> Loc.t Statement.VariableDeclaration.t * (Loc.t * Error.t) list 27 | val const: env -> Loc.t Statement.VariableDeclaration.t * (Loc.t * Error.t) list 28 | val var: env -> Loc.t Statement.VariableDeclaration.t * (Loc.t * Error.t) list 29 | val _function: env -> Loc.t Statement.t 30 | end 31 | 32 | module Declaration 33 | (Parse: Parser_common.PARSER) 34 | (Type: Type_parser.TYPE) 35 | : DECLARATION 36 | = struct 37 | let check_param = 38 | let rec pattern ((env, _) as check_env) (loc, p) = Pattern.(match p with 39 | | Object o -> _object check_env o 40 | | Array arr -> _array check_env arr 41 | | Assignment { Assignment.left; _ } -> pattern check_env left 42 | | Identifier id -> identifier_pattern check_env id 43 | | Expression _ -> ( 44 | error_at env (loc, Error.ExpectedPatternFoundExpression); 45 | check_env 46 | ) 47 | ) 48 | 49 | and _object check_env o = 50 | List.fold_left 51 | object_property 52 | check_env 53 | o.Pattern.Object.properties 54 | 55 | and object_property check_env = Pattern.Object.(function 56 | | Property (_, property) -> Property.( 57 | let check_env = match property.key with 58 | | Identifier id -> identifier_no_dupe_check check_env id 59 | | _ -> check_env in 60 | pattern check_env property.pattern) 61 | | RestProperty (_, { RestProperty.argument; }) -> 62 | pattern check_env argument) 63 | 64 | and _array check_env arr = 65 | List.fold_left 66 | array_element 67 | check_env 68 | arr.Pattern.Array.elements 69 | 70 | and array_element check_env = Pattern.Array.(function 71 | | None -> check_env 72 | | Some (Element p) -> pattern check_env p 73 | | Some (RestElement (_, { RestElement.argument; })) -> 74 | pattern check_env argument) 75 | 76 | and identifier_pattern check_env {Pattern.Identifier.name=id; _;} = 77 | identifier check_env id 78 | 79 | and identifier (env, param_names) (loc, name as id) = 80 | if SSet.mem name param_names 81 | then error_at env (loc, Error.StrictParamDupe); 82 | let env, param_names = 83 | identifier_no_dupe_check (env, param_names) id in 84 | env, SSet.add name param_names 85 | 86 | and identifier_no_dupe_check (env, param_names) (loc, name) = 87 | if is_restricted name 88 | then strict_error_at env (loc, Error.StrictParamName); 89 | if is_future_reserved name || is_strict_reserved name 90 | then strict_error_at env (loc, Error.StrictReservedWord); 91 | env, param_names 92 | 93 | in pattern 94 | 95 | (* Strict is true if we were already in strict mode or if we are newly in 96 | * strict mode due to a directive in the function. 97 | * Simple is the IsSimpleParameterList thing from the ES6 spec *) 98 | let strict_post_check env ~strict ~simple id (_, { Ast.Function.Params.params; rest }) = 99 | if strict || not simple 100 | then 101 | (* If we are doing this check due to strict mode than there are two 102 | * cases to consider. The first is when we were already in strict mode 103 | * and therefore already threw strict errors. In this case we want to 104 | * do these checks outside of strict mode. The other is if we 105 | * originally parsed in non-strict mode but now are strict. Then we 106 | * want to do these checks in strict mode *) 107 | let env = 108 | if strict 109 | then env |> with_strict (not (Parser_env.in_strict_mode env)) 110 | else env in 111 | (match id with 112 | | Some (loc, name) -> 113 | if is_restricted name 114 | then strict_error_at env (loc, Error.StrictFunctionName); 115 | if is_future_reserved name || is_strict_reserved name 116 | then strict_error_at env (loc, Error.StrictReservedWord) 117 | | None -> ()); 118 | let acc = List.fold_left check_param (env, SSet.empty) params in 119 | match rest with 120 | | Some (_, { Function.RestElement.argument }) -> 121 | ignore (check_param acc argument) 122 | | None -> 123 | () 124 | 125 | let function_params = 126 | let rec param env = 127 | let left = Parse.pattern env Error.StrictParamName in 128 | (* TODO: shouldn't Parse.pattern recognize Assignment patterns? *) 129 | if Peek.token env = T_ASSIGN 130 | then begin 131 | Expect.token env T_ASSIGN; 132 | let right = Parse.assignment env in 133 | let loc = Loc.btwn (fst left) (fst right) in 134 | (loc, Pattern.Assignment { Pattern.Assignment.left; right }) 135 | end else 136 | left 137 | and param_list env acc = 138 | match Peek.token env with 139 | | T_EOF 140 | | T_RPAREN 141 | | T_ELLIPSIS as t -> 142 | let rest = 143 | if t = T_ELLIPSIS then begin 144 | let start_loc = Peek.loc env in 145 | Expect.token env T_ELLIPSIS; 146 | let id = Parse.pattern env Error.StrictParamName in 147 | let loc = Loc.btwn start_loc (fst id) in 148 | Some (loc, { Function.RestElement.argument = id; }) 149 | end else 150 | None 151 | in 152 | if Peek.token env <> T_RPAREN 153 | then error env Error.ParameterAfterRestParameter; 154 | { Ast.Function.Params.params = List.rev acc; rest } 155 | | _ -> 156 | let the_param = param env in 157 | if Peek.token env <> T_RPAREN 158 | then Expect.token env T_COMMA; 159 | param_list env (the_param::acc) 160 | 161 | in fun ~await ~yield -> with_loc (fun env -> 162 | let env = env 163 | |> with_allow_await await 164 | |> with_allow_yield yield 165 | |> with_in_formal_parameters true 166 | in 167 | Expect.token env T_LPAREN; 168 | let params = param_list env [] in 169 | Expect.token env T_RPAREN; 170 | params 171 | ) 172 | 173 | let function_body env ~async ~generator = 174 | let env = enter_function env ~async ~generator in 175 | let loc, block, strict = Parse.function_block_body env in 176 | loc, Function.BodyBlock (loc, block), strict 177 | 178 | let concise_function_body env ~async ~generator = 179 | let env = env |> with_in_function true in 180 | match Peek.token env with 181 | | T_LCURLY -> 182 | let _, body, strict = function_body env ~async ~generator in 183 | body, strict 184 | | _ -> 185 | let env = enter_function env ~async ~generator in 186 | let expr = Parse.assignment env in 187 | Function.BodyExpression expr, in_strict_mode env 188 | 189 | let variance env is_async is_generator = 190 | let loc = Peek.loc env in 191 | let variance = match Peek.token env with 192 | | T_PLUS -> 193 | Eat.token env; 194 | Some (loc, Variance.Plus) 195 | | T_MINUS -> 196 | Eat.token env; 197 | Some (loc, Variance.Minus) 198 | | _ -> 199 | None 200 | in 201 | match variance with 202 | | Some (loc, _) when is_async || is_generator -> 203 | error_at env (loc, Error.UnexpectedVariance); 204 | None 205 | | _ -> 206 | variance 207 | 208 | let generator env = Expect.maybe env T_MULT 209 | 210 | let async env = Expect.maybe env T_ASYNC 211 | 212 | let is_simple_function_params = 213 | let is_simple_param = function 214 | | _, Pattern.Identifier _ -> true 215 | | _ -> false 216 | 217 | in fun (_, { Ast.Function.Params.params; rest }) -> 218 | rest = None && List.for_all is_simple_param params 219 | 220 | let _function env = 221 | let start_loc = Peek.loc env in 222 | let async = async env in 223 | Expect.token env T_FUNCTION; 224 | let generator = generator env in 225 | let (typeParameters, id) = ( 226 | match in_export env, Peek.token env with 227 | | true, T_LPAREN -> (None, None) 228 | | true, T_LESS_THAN -> 229 | let typeParams = Type.type_parameter_declaration env in 230 | let id = if Peek.token env = T_LPAREN then None else Some ( 231 | Parse.identifier ~restricted_error:Error.StrictFunctionName env 232 | ) in 233 | (typeParams, id) 234 | | _ -> 235 | let id = 236 | Parse.identifier ~restricted_error:Error.StrictFunctionName env 237 | in 238 | (Type.type_parameter_declaration env, Some id) 239 | ) in 240 | let params = 241 | let yield, await = match async, generator with 242 | | true, true -> true, true (* proposal-async-iteration/#prod-AsyncGeneratorDeclaration *) 243 | | true, false -> false, allow_await env (* #prod-AsyncFunctionDeclaration *) 244 | | false, true -> true, false (* #prod-GeneratorDeclaration *) 245 | | false, false -> false, false (* #prod-FunctionDeclaration *) 246 | in 247 | function_params ~await ~yield env 248 | in 249 | let (returnType, predicate) = Type.annotation_and_predicate_opt env in 250 | let _, body, strict = function_body env ~async ~generator in 251 | let simple = is_simple_function_params params in 252 | strict_post_check env ~strict ~simple id params; 253 | let end_loc, expression = Ast.Function.( 254 | match body with 255 | | BodyBlock (loc, _) -> loc, false 256 | | BodyExpression (loc, _) -> loc, true) in 257 | Loc.btwn start_loc end_loc, Statement.(FunctionDeclaration Function.({ 258 | id; 259 | params; 260 | body; 261 | generator; 262 | async; 263 | predicate; 264 | expression; 265 | returnType; 266 | typeParameters; 267 | })) 268 | 269 | let variable_declaration_list = 270 | let variable_declaration env = 271 | let loc, (decl, errs) = with_loc (fun env -> 272 | let id = Parse.pattern env Error.StrictVarName in 273 | let init, errs = if Peek.token env = T_ASSIGN 274 | then begin 275 | Expect.token env T_ASSIGN; 276 | Some (Parse.assignment env), [] 277 | end else Ast.Pattern.( 278 | match id with 279 | | _, Identifier _ -> None, [] 280 | | loc, _ -> None, [(loc, Error.NoUninitializedDestructuring)] 281 | ) in 282 | Ast.Statement.VariableDeclaration.Declarator.({ 283 | id; 284 | init; 285 | }), errs 286 | ) env in 287 | (loc, decl), errs 288 | 289 | in let rec helper env decls errs = 290 | let decl, errs_ = variable_declaration env in 291 | let decls = decl::decls in 292 | let errs = errs_ @ errs in 293 | if Peek.token env = T_COMMA 294 | then begin 295 | Expect.token env T_COMMA; 296 | helper env decls errs 297 | end else 298 | List.rev decls, List.rev errs 299 | 300 | in fun env -> helper env [] [] 301 | 302 | let declarations token kind env = 303 | Expect.token env token; 304 | let declarations, errs = variable_declaration_list env in 305 | Statement.VariableDeclaration.({ 306 | kind; 307 | declarations; 308 | }), errs 309 | 310 | let var = declarations T_VAR Statement.VariableDeclaration.Var 311 | 312 | let const env = 313 | let env = env |> with_no_let true in 314 | let variable, errs = 315 | declarations T_CONST Statement.VariableDeclaration.Const env in 316 | (* Make sure all consts defined are initialized *) 317 | let errs = Statement.VariableDeclaration.( 318 | List.fold_left (fun errs decl -> 319 | match decl with 320 | | loc, { Declarator.init = None; _ } -> 321 | (loc, Error.NoUninitializedConst)::errs 322 | | _ -> errs 323 | ) errs variable.declarations 324 | ) in 325 | variable, List.rev errs 326 | 327 | let let_ env = 328 | let env = env |> with_no_let true in 329 | declarations T_LET Statement.VariableDeclaration.Let env 330 | 331 | let variable env = 332 | let loc, (decl, errs) = with_loc (fun env -> 333 | let variable, errs = match Peek.token env with 334 | | T_CONST -> const env 335 | | T_LET -> let_ env 336 | | T_VAR -> var env 337 | | _ -> 338 | error_unexpected env; 339 | (* We need to return something. This is as good as anything else *) 340 | var env in 341 | Statement.VariableDeclaration variable, errs 342 | ) env in 343 | (loc, decl), errs 344 | end 345 | --------------------------------------------------------------------------------