├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── Cargo.toml ├── LICENSE ├── README.md ├── crates ├── database │ ├── Cargo.toml │ └── src │ │ ├── arena.rs │ │ ├── builtin │ │ ├── constructors.rs │ │ ├── mod.rs │ │ └── tycons.rs │ │ ├── check.rs │ │ ├── database.rs │ │ ├── lib.rs │ │ └── types.rs └── sml-analyzer │ ├── Cargo.toml │ └── src │ ├── completions.rs │ ├── dispatch.rs │ ├── main.rs │ ├── state.rs │ ├── types.rs │ └── util.rs ├── demo.gif ├── demo.png ├── package-lock.json ├── package.json ├── src └── extension.ts ├── syntaxes └── sml.tmLanguage.json ├── test.sml └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | out 5 | node_modules -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "dbaeumer.vscode-eslint" 8 | ] 9 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "name": "Launch Client", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}"], 11 | "outFiles": ["${workspaceRoot}/client/out/**/*.js"], 12 | "preLaunchTask": { 13 | "type": "npm", 14 | "script": "watch" 15 | } 16 | }, 17 | { 18 | "type": "node", 19 | "request": "attach", 20 | "name": "Attach to Server", 21 | "port": 6009, 22 | "restart": true, 23 | "outFiles": ["${workspaceRoot}/server/out/**/*.js"] 24 | } 25 | ], 26 | "compounds": [ 27 | { 28 | "name": "Client + Server", 29 | "configurations": ["Launch Client", "Attach to Server"] 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.insertSpaces": false, 3 | "tslint.enable": true, 4 | "typescript.tsc.autoDetect": "off", 5 | "typescript.preferences.quoteStyle": "single", 6 | "editor.codeActionsOnSave": { 7 | "source.fixAll.eslint": true 8 | } 9 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "compile", 7 | "group": "build", 8 | "presentation": { 9 | "panel": "dedicated", 10 | "reveal": "never" 11 | }, 12 | "problemMatcher": [ 13 | "$tsc" 14 | ] 15 | }, 16 | { 17 | "type": "npm", 18 | "script": "watch", 19 | "isBackground": true, 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | }, 24 | "presentation": { 25 | "panel": "dedicated", 26 | "reveal": "never" 27 | }, 28 | "problemMatcher": [ 29 | "$tsc-watch" 30 | ] 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crates/database", 4 | "crates/sml-analyzer" 5 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Michael Lazear 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sml-analyzer 2 | 3 | An experimental language-server for SomewhatML that provides: 4 | 5 | - Completions 6 | - Provide type information on hover 7 | - Goto definition support 8 | - Inline error reporting (syntax and type unification) 9 | 10 | ![Demo](demo.gif) 11 | 12 | ``` 13 | cargo build 14 | ``` 15 | 16 | then follow the instructions below 17 | 18 | ## Running sml-analyzer 19 | 20 | - Run `npm install` in this folder. This installs all necessary npm modules in both the client and server folder 21 | - Open VS Code on this folder. 22 | - Press Ctrl+Shift+B to compile the client and server. 23 | - Switch to the Debug viewlet. 24 | - Select `Launch Client` from the drop down. 25 | - Run the launch config. 26 | - If you want to debug the server as well use the launch configuration `Attach to Server` 27 | - In the [Extension Development Host] instance of VSCode, open a document in 'plain text' language mode. 28 | - Type `j` or `t` to see `Javascript` and `TypeScript` completion. 29 | - Enter text content such as `AAA aaa BBB`. The extension will emit diagnostics for all words in all-uppercase. 30 | -------------------------------------------------------------------------------- /crates/database/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "database" 3 | version = "0.1.0" 4 | authors = ["Michael Lazear "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | sml-util = { git = "https://github.com/SomewhatML/sml-compiler/" } 11 | sml-frontend = { git = "https://github.com/SomewhatML/sml-compiler/" } 12 | sml-core = { git = "https://github.com/SomewhatML/sml-compiler/" } 13 | typed-arena = "2.0" 14 | log = "0.4.3" -------------------------------------------------------------------------------- /crates/database/src/arena.rs: -------------------------------------------------------------------------------- 1 | use super::{Row, SortedRecord, Span, Symbol}; 2 | use crate::builtin; 3 | use crate::types::{Type, TypeVar}; 4 | use std::cell::Cell; 5 | use typed_arena; 6 | 7 | pub struct OwnedArena<'arena> { 8 | types: typed_arena::Arena>, 9 | vars: typed_arena::Arena>, 10 | } 11 | 12 | impl<'arena> OwnedArena<'arena> { 13 | pub fn new() -> OwnedArena<'arena> { 14 | OwnedArena { 15 | types: typed_arena::Arena::with_capacity(4096), 16 | vars: typed_arena::Arena::with_capacity(4096), 17 | } 18 | } 19 | 20 | // borrowck is easily assuaged here 21 | pub fn borrow(&'arena self) -> Arena<'arena> { 22 | Arena::new(&self.types, &self.vars) 23 | } 24 | } 25 | 26 | pub struct Arena<'ar> { 27 | types: &'ar typed_arena::Arena>, 28 | vars: &'ar typed_arena::Arena>, 29 | fresh: Cell, 30 | 31 | // We cache the builtin nullary type constructors 32 | _exn: &'ar Type<'ar>, 33 | _bool: &'ar Type<'ar>, 34 | _int: &'ar Type<'ar>, 35 | _str: &'ar Type<'ar>, 36 | _char: &'ar Type<'ar>, 37 | _unit: &'ar Type<'ar>, 38 | } 39 | 40 | impl<'ar> Arena<'ar> { 41 | pub fn new( 42 | types: &'ar typed_arena::Arena>, 43 | vars: &'ar typed_arena::Arena>, 44 | ) -> Arena<'ar> { 45 | let _exn = types.alloc(Type::Con(builtin::tycons::T_EXN, Vec::new())); 46 | let _bool = types.alloc(Type::Con(builtin::tycons::T_BOOL, Vec::new())); 47 | let _int = types.alloc(Type::Con(builtin::tycons::T_INT, Vec::new())); 48 | let _str = types.alloc(Type::Con(builtin::tycons::T_STRING, Vec::new())); 49 | let _char = types.alloc(Type::Con(builtin::tycons::T_CHAR, Vec::new())); 50 | let _unit = types.alloc(Type::Con(builtin::tycons::T_UNIT, Vec::new())); 51 | 52 | Arena { 53 | types, 54 | vars, 55 | fresh: Cell::new(0), 56 | _exn, 57 | _bool, 58 | _int, 59 | _str, 60 | _char, 61 | _unit, 62 | } 63 | } 64 | 65 | pub fn alloc(&self, ty: Type<'ar>) -> &'ar Type<'ar> { 66 | self.types.alloc(ty) 67 | } 68 | 69 | pub fn fresh_var(&self, rank: usize) -> &'ar Type<'ar> { 70 | let tvar = self.fresh_type_var(rank); 71 | self.types.alloc(Type::Var(tvar)) 72 | } 73 | 74 | pub fn fresh_type_var(&self, rank: usize) -> &'ar TypeVar<'ar> { 75 | let x = self.fresh.get(); 76 | self.fresh.set(x + 1); 77 | self.vars.alloc(TypeVar::new(x, rank)) 78 | } 79 | 80 | pub fn alloc_tuple>>(&self, iter: I) -> &'ar Type<'ar> { 81 | let rows = iter 82 | .into_iter() 83 | .enumerate() 84 | .map(|(idx, ty)| Row { 85 | label: Symbol::tuple_field(idx as u32 + 1), 86 | data: self.alloc(ty), 87 | span: Span::dummy(), 88 | }) 89 | .collect(); 90 | 91 | self.alloc(Type::Record(SortedRecord::new_unchecked(rows))) 92 | } 93 | 94 | pub fn tuple>>(&self, iter: I) -> &'ar Type<'ar> { 95 | let rows = iter 96 | .into_iter() 97 | .enumerate() 98 | .map(|(idx, ty)| Row { 99 | label: Symbol::tuple_field(idx as u32 + 1), 100 | data: ty, 101 | span: Span::dummy(), 102 | }) 103 | .collect(); 104 | 105 | self.alloc(Type::Record(SortedRecord::new_unchecked(rows))) 106 | } 107 | 108 | pub fn exn(&self) -> &'ar Type<'ar> { 109 | self._exn 110 | } 111 | 112 | pub fn unit(&self) -> &'ar Type<'ar> { 113 | self._unit 114 | } 115 | 116 | pub fn char(&self) -> &'ar Type<'ar> { 117 | self._char 118 | } 119 | 120 | pub fn int(&self) -> &'ar Type<'ar> { 121 | self._int 122 | } 123 | 124 | pub fn bool(&self) -> &'ar Type<'ar> { 125 | self._bool 126 | } 127 | 128 | pub fn string(&self) -> &'ar Type<'ar> { 129 | self._str 130 | } 131 | 132 | pub fn reff(&self, ty: &'ar Type<'ar>) -> &'ar Type<'ar> { 133 | self.types 134 | .alloc(Type::Con(builtin::tycons::T_REF, vec![ty])) 135 | } 136 | 137 | pub fn list(&self, ty: &'ar Type<'ar>) -> &'ar Type<'ar> { 138 | self.types 139 | .alloc(Type::Con(builtin::tycons::T_LIST, vec![ty])) 140 | } 141 | 142 | pub fn arrow(&self, dom: &'ar Type<'ar>, rng: &'ar Type<'ar>) -> &'ar Type<'ar> { 143 | self.types 144 | .alloc(Type::Con(builtin::tycons::T_ARROW, vec![dom, rng])) 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /crates/database/src/builtin/constructors.rs: -------------------------------------------------------------------------------- 1 | //! Beware that type_ids are hardcoded in this file, corresponding to the order 2 | //! of the builtin type constructors defined in `tycons.rs`. Changing the order 3 | //! there, or the order in which the constructors are defined in the environment 4 | //! may have disastrous effects. 5 | use crate::*; 6 | use sml_util::interner::*; 7 | 8 | // datatype 'a list = nil | :: of 'a * 'a list 9 | pub const C_NIL: Constructor = Constructor { 10 | name: S_NIL, 11 | type_id: TypeId(6), 12 | tag: 0, 13 | arity: 0, 14 | type_arity: 2, 15 | }; 16 | pub const C_CONS: Constructor = Constructor { 17 | name: S_CONS, 18 | type_id: TypeId(6), 19 | tag: 1, 20 | arity: 1, 21 | type_arity: 2, 22 | }; 23 | 24 | // datatype bool = true | false 25 | pub const C_TRUE: Constructor = Constructor { 26 | name: S_TRUE, 27 | type_id: TypeId(7), 28 | tag: 0, 29 | arity: 0, 30 | type_arity: 2, 31 | }; 32 | pub const C_FALSE: Constructor = Constructor { 33 | name: S_FALSE, 34 | type_id: TypeId(7), 35 | tag: 1, 36 | arity: 0, 37 | type_arity: 2, 38 | }; 39 | 40 | pub const C_REF: Constructor = Constructor { 41 | name: S_REF, 42 | type_id: TypeId(5), 43 | tag: 0, 44 | arity: 1, 45 | type_arity: 1, 46 | }; 47 | 48 | pub const C_BUILTINS: [Constructor; 5] = [C_NIL, C_CONS, C_TRUE, C_FALSE, C_REF]; 49 | -------------------------------------------------------------------------------- /crates/database/src/builtin/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constructors; 2 | pub mod tycons; 3 | 4 | use super::*; 5 | use crate::database::*; 6 | 7 | fn define_constructor<'arena>(ctx: &mut Database<'arena>, con: Constructor, sch: Scheme<'arena>) { 8 | ctx.define_value(con.name, sch, IdStatus::Con(con), Span::zero()); 9 | } 10 | 11 | /// This is not pretty, but we have to handle builtins for elaboration somehow 12 | pub fn populate_context<'arena>(ctx: &mut Database<'arena>) { 13 | // Build the initial type environment 14 | for tc in &tycons::T_BUILTINS { 15 | ctx.define_type(tc.name, TypeStructure::Tycon(*tc), Span::zero()); 16 | } 17 | 18 | let nil = ctx.arena.fresh_var(0); 19 | 20 | define_constructor( 21 | ctx, 22 | constructors::C_NIL, 23 | Scheme::Poly(vec![nil.tyvar_id()], ctx.arena.list(nil)), 24 | ); 25 | 26 | let cons = ctx.arena.fresh_var(0); 27 | 28 | // The inner types of cons: 'a * 'a list 29 | let crec = ctx.arena.tuple(vec![cons, ctx.arena.list(cons)]); 30 | 31 | define_constructor( 32 | ctx, 33 | constructors::C_CONS, 34 | Scheme::Poly( 35 | vec![cons.tyvar_id()], 36 | ctx.arena.arrow(crec, ctx.arena.list(cons)), 37 | ), 38 | ); 39 | 40 | define_constructor(ctx, constructors::C_TRUE, Scheme::Mono(ctx.arena.bool())); 41 | 42 | define_constructor(ctx, constructors::C_FALSE, Scheme::Mono(ctx.arena.bool())); 43 | 44 | let reff = ctx.arena.fresh_var(0); 45 | define_constructor( 46 | ctx, 47 | constructors::C_REF, 48 | Scheme::Poly( 49 | vec![reff.tyvar_id()], 50 | ctx.arena.arrow(reff, ctx.arena.reff(reff)), 51 | ), 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /crates/database/src/builtin/tycons.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | use sml_util::interner::*; 3 | 4 | pub const T_ARROW: Tycon = Tycon::new(S_ARROW, 2); 5 | pub const T_UNIT: Tycon = Tycon::new(S_UNIT, 0); 6 | pub const T_CHAR: Tycon = Tycon::new(S_CHAR, 0); 7 | pub const T_INT: Tycon = Tycon::new(S_INT, 0); 8 | pub const T_STRING: Tycon = Tycon::new(S_STRING, 0); 9 | pub const T_REF: Tycon = Tycon::new(S_REF, 1); 10 | pub const T_LIST: Tycon = Tycon::new(S_LIST, 1); 11 | pub const T_BOOL: Tycon = Tycon::new(S_BOOL, 0); 12 | pub const T_EXN: Tycon = Tycon::new(S_EXN, 0); 13 | 14 | pub const T_BUILTINS: [Tycon; 9] = [ 15 | T_ARROW, T_UNIT, T_CHAR, T_INT, T_STRING, T_REF, T_LIST, T_BOOL, T_EXN, 16 | ]; 17 | -------------------------------------------------------------------------------- /crates/database/src/check.rs: -------------------------------------------------------------------------------- 1 | //! Walk the AST and perform syntax checking, as defined in Section 2.9 2 | //! 3 | //! * No expression row, pat row, or type row may bind the same label twice 4 | //! * valbind, typbind, datbind, exbinds may not bind the same identifier twice 5 | //! * No tyvarseq may contain the same `tyvar` twice 6 | //! * For each recursive `pat=exp` valbind, exp must be of the form `fn match` 7 | //! * No datbind, valbind, or exnbind may bind `true`, `false`, `nil`, `::`, or `ref` 8 | //! * No datbind or exnbind may bind `it` 9 | //! * No real constant may occur in a pattern 10 | //! * tyvarseqs across the same valbinds must be unique 11 | 12 | use sml_frontend::ast::*; 13 | use sml_util::diagnostics::Diagnostic; 14 | use sml_util::interner::*; 15 | use sml_util::span::Span; 16 | 17 | use std::collections::{HashSet, VecDeque}; 18 | 19 | const BUILTIN_CONSTRUCTORS: [Symbol; 5] = [S_NIL, S_CONS, S_TRUE, S_FALSE, S_REF]; 20 | 21 | #[derive(Default, Debug)] 22 | pub struct Check { 23 | pub diags: Vec, 24 | } 25 | 26 | impl Check { 27 | pub fn check_program(program: &[Decl]) -> Vec { 28 | let mut check = Check { diags: Vec::new() }; 29 | for d in program { 30 | check.check_decl(d); 31 | } 32 | check.diags 33 | } 34 | 35 | fn check_pat(&mut self, pattern: &Pat) { 36 | use PatKind::*; 37 | let mut vars = HashSet::new(); 38 | let mut queue = VecDeque::new(); 39 | queue.push_back(pattern); 40 | while let Some(pat) = queue.pop_front() { 41 | match &pat.data { 42 | App(_, _) => unreachable!(), 43 | Ascribe(p, _) => { 44 | queue.push_back(p); 45 | } 46 | Const(_) => {} 47 | FlatApp(pats) | List(pats) => { 48 | for pat in pats { 49 | queue.push_back(pat) 50 | } 51 | } 52 | Record(rows, _) => { 53 | self.check_rows(rows, |c, p| c.check_pat(p)); 54 | } 55 | Variable(sym) => { 56 | if !sym.builtin() { 57 | if !vars.insert(*sym) { 58 | self.diags.push( 59 | Diagnostic::error( 60 | pattern.span, 61 | format!("duplicate variable in pattern: '{:?}'", sym), 62 | ) 63 | .message(pat.span, "redefined here"), 64 | ); 65 | } 66 | } 67 | } 68 | Wild => {} 69 | } 70 | } 71 | } 72 | 73 | fn check_rows(&mut self, rows: &[Row], mut f: F) { 74 | let mut set = HashSet::new(); 75 | for row in rows { 76 | if !set.insert(row.label) { 77 | self.diags.push(Diagnostic::error( 78 | row.span, 79 | format!("duplicate record label: '{:?}'", row.label), 80 | )); 81 | } 82 | f(self, &row.data); 83 | } 84 | } 85 | 86 | fn check_expr(&mut self, expr: &Expr) { 87 | use ExprKind::*; 88 | match &expr.data { 89 | Andalso(e1, e2) => { 90 | self.check_expr(e1); 91 | self.check_expr(e2); 92 | } 93 | App(e1, e2) => { 94 | self.check_expr(e1); 95 | self.check_expr(e2); 96 | } 97 | Case(expr, rules) => { 98 | self.check_expr(expr); 99 | for rule in rules { 100 | self.check_pat(&rule.pat); 101 | self.check_expr(&rule.expr); 102 | } 103 | } 104 | Const(_) => {} 105 | Constraint(expr, _) => { 106 | self.check_expr(expr); 107 | } 108 | FlatApp(exprs) => { 109 | for expr in exprs { 110 | self.check_expr(expr); 111 | } 112 | } 113 | Fn(rules) => { 114 | for rule in rules { 115 | self.check_pat(&rule.pat); 116 | self.check_expr(&rule.expr); 117 | } 118 | } 119 | Handle(expr, rules) => { 120 | self.check_expr(expr); 121 | for rule in rules { 122 | self.check_pat(&rule.pat); 123 | self.check_expr(&rule.expr); 124 | } 125 | } 126 | If(e1, e2, e3) => { 127 | self.check_expr(e1); 128 | self.check_expr(e2); 129 | self.check_expr(e3); 130 | } 131 | Let(decls, expr) => { 132 | for decl in decls { 133 | self.check_decl(decl); 134 | } 135 | self.check_expr(expr); 136 | } 137 | List(exprs) => { 138 | for expr in exprs { 139 | self.check_expr(expr); 140 | } 141 | } 142 | Orelse(e1, e2) => { 143 | self.check_expr(e1); 144 | self.check_expr(e2); 145 | } 146 | Primitive(_) => {} 147 | Raise(expr) => { 148 | self.check_expr(expr); 149 | } 150 | Record(rows) => { 151 | self.check_rows(rows, |c, e| c.check_expr(e)); 152 | } 153 | Selector(_) => {} 154 | Seq(exprs) => { 155 | for expr in exprs { 156 | self.check_expr(expr); 157 | } 158 | } 159 | Var(_) => {} 160 | While(_, _) => { 161 | self.diags 162 | .push(Diagnostic::error(expr.span, "`while` exprs not supported")); 163 | } 164 | } 165 | } 166 | 167 | fn check_tyvars(&mut self, sp: Span, tyvars: &[Symbol]) { 168 | let mut set = HashSet::new(); 169 | for tv in tyvars { 170 | if !set.insert(tv) { 171 | self.diags.push(Diagnostic::error( 172 | sp, 173 | format!("type variable '{:?}' cannot be rebound", tv), 174 | )); 175 | } 176 | } 177 | } 178 | 179 | fn check_datatype(&mut self, datbinds: &[Datatype]) { 180 | for db in datbinds { 181 | // check for duplicate tyvar or constructors 182 | self.check_tyvars(db.span, &db.tyvars); 183 | self.check_rows(&db.constructors, |_, _| ()); 184 | 185 | for con in &db.constructors { 186 | if BUILTIN_CONSTRUCTORS.contains(&con.label) { 187 | self.diags.push(Diagnostic::error( 188 | con.span, 189 | format!( 190 | "builtin data constructor '{:?}' cannot be rebound", 191 | con.label 192 | ), 193 | )); 194 | } 195 | } 196 | } 197 | } 198 | 199 | fn check_variants(&mut self, datbinds: &[Variant]) { 200 | self.check_rows(datbinds, |_, _| {}); 201 | } 202 | 203 | fn check_valbinds(&mut self, sp: Span, tyvars: &[Symbol], pat: &Pat, expr: &Expr) { 204 | self.check_tyvars(sp, tyvars); 205 | if let PatKind::Variable(s) = pat.data { 206 | if BUILTIN_CONSTRUCTORS.contains(&s) { 207 | self.diags.push(Diagnostic::error( 208 | pat.span, 209 | format!("builtin data constructor '{:?}' cannot be rebound", s), 210 | )); 211 | } 212 | } 213 | self.check_pat(pat); 214 | self.check_expr(expr); 215 | } 216 | 217 | fn check_funbinds(&mut self, sp: Span, tyvars: &[Symbol], fbs: &[Fun]) { 218 | self.check_tyvars(sp, tyvars); 219 | let mut names = HashSet::new(); 220 | for f in fbs { 221 | let n = f[0].name; 222 | let a = f[0].pats.len(); 223 | for fb in f.iter() { 224 | if n != fb.name { 225 | self.diags.push(Diagnostic::error( 226 | fb.span, 227 | format!( 228 | "function clause with a different name; expected: {:?}, found {:?}", 229 | n, fb.name 230 | ), 231 | )); 232 | } 233 | if a != fb.pats.len() { 234 | self.diags.push(Diagnostic::error( 235 | fb.span, 236 | format!( 237 | "function clause with a different number of args; expected: {:?}, found {:?}", 238 | a, fb.pats.len() 239 | ) 240 | )); 241 | } 242 | } 243 | if !names.insert(n) { 244 | self.diags.push(Diagnostic::error( 245 | f.span, 246 | format!( 247 | "function '{:?}' was previously defined in function bindings", 248 | n 249 | ), 250 | )); 251 | } 252 | } 253 | } 254 | 255 | pub fn check_decl(&mut self, decl: &Decl) { 256 | use DeclKind::*; 257 | match &decl.data { 258 | Datatype(datbinds) => { 259 | self.check_datatype(datbinds); 260 | if datbinds.len() >= 255 { 261 | self.diags.push(Diagnostic::error( 262 | decl.span, 263 | format!("maximum of 255 mutually recursive datatypes"), 264 | )); 265 | } 266 | } 267 | Type(_) => {} 268 | Function(tyvars, fbs) => self.check_funbinds(decl.span, tyvars, fbs), 269 | Value(tyvars, pat, expr) => self.check_valbinds(decl.span, tyvars, pat, expr), 270 | Exception(vars) => { 271 | self.check_variants(vars); 272 | if vars.len() >= 255 { 273 | self.diags.push(Diagnostic::error( 274 | decl.span, 275 | format!("maximum of 255 mutually recursive datatypes"), 276 | )); 277 | } 278 | } 279 | Fixity(_, _, _) => {} 280 | Local(d1, d2) => { 281 | self.check_decl(d1); 282 | self.check_decl(d2); 283 | } 284 | Seq(decls) => { 285 | for decl in decls { 286 | self.check_decl(decl); 287 | } 288 | } 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /crates/database/src/database.rs: -------------------------------------------------------------------------------- 1 | //! The central database of sml-analyzer 2 | 3 | use super::*; 4 | use crate::arena::Arena; 5 | use std::cell::Cell; 6 | use std::collections::HashMap; 7 | 8 | use sml_frontend::ast; 9 | use sml_frontend::parser::precedence::{self, Fixity, Precedence, Query}; 10 | use sml_util::diagnostics::Diagnostic; 11 | 12 | pub struct Database<'ar> { 13 | // This vector contains all types defined throughout the program, 14 | // regardless of scope. [`Namespace`] structs are required to determine 15 | // which types are actually in scope 16 | pub types: Vec>>, 17 | // And likewise for all values/bindings defined throughout the program 18 | values: Vec>>, 19 | 20 | // Index into `namespaces`, representing the current scope 21 | current: usize, 22 | // An append-only list of [`Namespace`] structs, but this is a not stack. 23 | // Namespaces should only be pushed onto the end, and never deleted or re-ordered 24 | namespaces: Vec, 25 | 26 | // Essentially tracks the current declaration depth. This allows us to perform 27 | // rapid level-based type generalization 28 | tyvar_rank: usize, 29 | 30 | // stacks for alpha-renaming of explicity named type variables [x: 'a] 31 | tyvars: Vec<(Symbol, &'ar TypeVar<'ar>)>, 32 | 33 | // Generate dummy variable names, mostly for error handling 34 | gensym: Cell, 35 | 36 | local: bool, 37 | 38 | // Arena for type allocation 39 | pub arena: &'ar Arena<'ar>, 40 | 41 | pub bindings: Vec<(Span, &'ar Type<'ar>)>, 42 | pub references: Vec<(Span, Symbol)>, 43 | 44 | // Append-only vector of warnings/errors we generate 45 | pub diags: Vec, 46 | 47 | pub unification_errors: Vec>, 48 | } 49 | 50 | pub struct CantUnify<'ar> { 51 | pub ty1: &'ar Type<'ar>, 52 | pub ty2: &'ar Type<'ar>, 53 | pub sp1: Option, 54 | pub sp2: Option, 55 | pub message: String, 56 | pub reason: String, 57 | pub originating: Option, 58 | } 59 | 60 | impl<'ar> CantUnify<'ar> { 61 | pub fn new(ty1: &'ar Type<'ar>, ty2: &'ar Type<'ar>) -> CantUnify<'ar> { 62 | CantUnify { 63 | ty1, 64 | ty2, 65 | sp1: None, 66 | sp2: None, 67 | message: String::new(), 68 | reason: String::new(), 69 | originating: None, 70 | } 71 | } 72 | 73 | pub fn add_message>(mut self, s: S) -> Self { 74 | self.message = s.into(); 75 | self 76 | } 77 | 78 | pub fn add_reason>(mut self, s: S) -> Self { 79 | self.reason = s.into(); 80 | self 81 | } 82 | 83 | pub fn span(mut self, sp: Span) -> Self { 84 | self.originating = Some(sp); 85 | self 86 | } 87 | 88 | pub fn add_spans(mut self, s1: Span, s2: Span) -> Self { 89 | self.sp1 = Some(s1); 90 | self.sp2 = Some(s2); 91 | self 92 | } 93 | } 94 | 95 | /// An environment scope, that can hold a collection of type, expr, and infix bindings 96 | /// 97 | /// This typically corresponds to a source-level scope (e.g. function, let bindings) 98 | #[derive(Default, Debug)] 99 | pub struct Namespace { 100 | parent: Option, 101 | types: HashMap, 102 | values: HashMap, 103 | infix: HashMap, 104 | 105 | span: Span, 106 | } 107 | 108 | /// Identifier status for the Value Environment, as defined in the Defn. 109 | #[derive(Copy, Clone, Debug)] 110 | pub enum IdStatus { 111 | Exn(Constructor), 112 | Con(Constructor), 113 | Var, 114 | } 115 | 116 | /// Essentially a minimized Value Environment (VE) containing only datatype 117 | /// constructors, and without the indirection of going from names->id->def 118 | #[derive(Clone)] 119 | pub struct Cons<'ar> { 120 | name: Symbol, 121 | span: Span, 122 | scheme: Scheme<'ar>, 123 | } 124 | 125 | /// [`TypeStructure`], a TyStr from the Defn. This is a component of the 126 | /// Type Environment, TE 127 | #[derive(Clone)] 128 | pub enum TypeStructure<'ar> { 129 | /// TyStr (t, VE), a datatype 130 | Datatype(Tycon, Vec>), 131 | /// TyStr (_, VE), a definition. Rather than include a whole VE hashmap, 132 | /// we can include just a single entry 133 | Scheme(Scheme<'ar>), 134 | /// TyStr (t, {}), a name 135 | Tycon(Tycon), 136 | } 137 | 138 | impl<'ar> TypeStructure<'ar> { 139 | pub fn arity(&self) -> usize { 140 | match self { 141 | TypeStructure::Tycon(con) | TypeStructure::Datatype(con, _) => con.arity, 142 | TypeStructure::Scheme(s) => s.arity(), 143 | } 144 | } 145 | 146 | pub fn apply(&self, arena: &'ar Arena<'ar>, args: Vec<&'ar Type<'ar>>) -> &'ar Type<'ar> { 147 | match self { 148 | TypeStructure::Tycon(con) | TypeStructure::Datatype(con, _) => { 149 | arena.alloc(Type::Con(*con, args)) 150 | } 151 | TypeStructure::Scheme(s) => s.apply(arena, args), 152 | } 153 | } 154 | } 155 | 156 | #[derive(Clone)] 157 | pub struct ValueStructure<'ar> { 158 | scheme: Scheme<'ar>, 159 | status: IdStatus, 160 | } 161 | 162 | impl Namespace { 163 | pub fn with_parent(id: usize) -> Namespace { 164 | Namespace { 165 | parent: Some(id), 166 | types: HashMap::with_capacity(32), 167 | values: HashMap::with_capacity(64), 168 | infix: HashMap::with_capacity(16), 169 | span: Span::zero(), 170 | } 171 | } 172 | } 173 | 174 | /// Iterator over the namespace hierarchy, proceeding towards the root namespace 175 | pub struct NamespaceIter<'db, 'ar> { 176 | ctx: &'db Database<'ar>, 177 | ptr: Option, 178 | } 179 | 180 | impl<'db, 'ar> Iterator for NamespaceIter<'db, 'ar> { 181 | type Item = &'db Namespace; 182 | fn next(&mut self) -> Option { 183 | let n = self.ptr?; 184 | let ns = &self.ctx.namespaces[n]; 185 | self.ptr = ns.parent; 186 | Some(ns) 187 | } 188 | } 189 | 190 | /// A partially elaborated Vec 191 | struct PartialFun<'s, 'ar> { 192 | name: Symbol, 193 | clauses: Vec>, 194 | /// The resulting type 195 | res_ty: &'ar Type<'ar>, 196 | /// The overall flattened type, where for each ty_i in args, we have 197 | /// ty_0 -> ty_1 -> ... ty_arity -> res_ty 198 | ty: &'ar Type<'ar>, 199 | } 200 | 201 | /// A partially elaborated ast::FnBinding 202 | struct PartialFnBinding<'s, 'ar> { 203 | /// Function body 204 | expr: &'s ast::Expr, 205 | /// A list of variables bound in `pats`, and fresh type variables 206 | /// to be associated with those symbols 207 | bindings: Vec<(Spanned, &'ar Type<'ar>)>, 208 | span: Span, 209 | } 210 | 211 | impl<'ar> Database<'ar> { 212 | pub fn new(arena: &'ar Arena<'ar>) -> Database<'ar> { 213 | let mut ctx = Database { 214 | tyvars: Vec::default(), 215 | namespaces: Vec::default(), 216 | current: 0, 217 | tyvar_rank: 0, 218 | gensym: Cell::new(0), 219 | types: Vec::default(), 220 | values: Vec::default(), 221 | diags: Vec::default(), 222 | unification_errors: Vec::default(), 223 | local: false, 224 | bindings: Vec::default(), 225 | references: Vec::default(), 226 | arena, 227 | }; 228 | ctx.namespaces.push(Namespace::default()); 229 | builtin::populate_context(&mut ctx); 230 | ctx.elab_decl_fixity(&ast::Fixity::Infixr, 4, builtin::constructors::C_CONS.name); 231 | ctx 232 | } 233 | /// Keep track of the type variable stack, while executing the combinator 234 | /// function `f` on `self`. Any stack growth is popped off after `f` 235 | /// returns. 236 | fn with_tyvars) -> T>(&mut self, mut f: F) -> T { 237 | let n = self.tyvars.len(); 238 | let r = f(self); 239 | while self.tyvars.len() != n { 240 | self.tyvars.pop(); 241 | } 242 | r 243 | } 244 | 245 | /// Handle namespacing. The method creates a new child namespace, enters it 246 | /// and then calls `f`. After `f` has returned, the current scope is 247 | /// returned to it's previous value 248 | fn with_scope) -> T>(&mut self, f: F) -> T { 249 | let prev = self.current; 250 | let next = self.namespaces.len(); 251 | self.namespaces.push(Namespace::with_parent(prev)); 252 | self.current = next; 253 | let r = f(self); 254 | 255 | self.current = prev; 256 | r 257 | } 258 | 259 | /// Naively find the [`Namespace`] idx belonging to a [`Span`] 260 | fn get_ns_span(&self, loc: Location) -> usize { 261 | self.namespaces 262 | .iter() 263 | .enumerate() 264 | .filter(|(_, ns)| loc.line >= ns.span.start.line && loc.line < ns.span.end.line) 265 | .last() 266 | .map(|(idx, _)| idx) 267 | .unwrap_or_default() 268 | } 269 | 270 | pub fn in_scope_types(&self, loc: Location) -> Vec<(Symbol, Option<&'ar Type<'ar>>)> { 271 | let mut v = Vec::new(); 272 | let iter = NamespaceIter { 273 | ctx: &self, 274 | ptr: Some(self.get_ns_span(loc)), 275 | }; 276 | for ns in iter { 277 | for (sym, id) in &ns.types { 278 | if let Some(Spanned { span, data }) = self.types.get(id.0 as usize) { 279 | let inst = match data { 280 | TypeStructure::Tycon(_) => None, 281 | TypeStructure::Scheme(s) => Some(self.instantiate(&s)), 282 | TypeStructure::Datatype(_, _) => None, 283 | }; 284 | if loc.line >= span.start.line { 285 | v.push((*sym, inst)); 286 | } 287 | } 288 | } 289 | } 290 | 291 | v 292 | } 293 | 294 | pub fn in_scope_values(&self, loc: Location) -> Vec<(Symbol, &'ar Type<'ar>)> { 295 | let mut v = Vec::new(); 296 | let iter = NamespaceIter { 297 | ctx: &self, 298 | ptr: Some(self.get_ns_span(loc)), 299 | }; 300 | for ns in iter { 301 | for (sym, id) in &ns.values { 302 | if let Some(Spanned { span, data }) = self.values.get(id.0 as usize) { 303 | let inst = self.instantiate(&data.scheme); 304 | if loc.line >= span.start.line { 305 | v.push((*sym, inst)); 306 | } 307 | } 308 | } 309 | } 310 | 311 | v 312 | } 313 | 314 | pub fn in_scope_value_names(&self, loc: Location) -> Vec> { 315 | let mut v = Vec::new(); 316 | let iter = NamespaceIter { 317 | ctx: &self, 318 | ptr: Some(self.get_ns_span(loc)), 319 | }; 320 | for ns in iter { 321 | for (sym, id) in &ns.values { 322 | if let Some(Spanned { span, .. }) = self.values.get(id.0 as usize) { 323 | if loc.line >= span.start.line { 324 | v.push(Spanned { 325 | span: *span, 326 | data: *sym, 327 | }); 328 | } 329 | } 330 | } 331 | } 332 | 333 | v 334 | } 335 | 336 | /// Globally define a type 337 | pub(crate) fn define_type( 338 | &mut self, 339 | sym: Symbol, 340 | tystr: TypeStructure<'ar>, 341 | span: Span, 342 | ) -> TypeId { 343 | let id = TypeId(self.types.len() as u32); 344 | self.types.push(Spanned::new(tystr, span)); 345 | let ns = if self.local { 346 | self.namespaces[self.current].parent.unwrap_or(self.current) 347 | } else { 348 | self.current 349 | }; 350 | self.namespaces[ns].types.insert(sym, id); 351 | id 352 | } 353 | 354 | /// Globally define a value 355 | pub(crate) fn define_value( 356 | &mut self, 357 | sym: Symbol, 358 | scheme: Scheme<'ar>, 359 | status: IdStatus, 360 | span: Span, 361 | ) -> ExprId { 362 | let id = ExprId(self.values.len() as u32); 363 | let ns = if self.local { 364 | self.namespaces[self.current].parent.unwrap_or(self.current) 365 | } else { 366 | self.current 367 | }; 368 | self.values 369 | .push(Spanned::new(ValueStructure { scheme, status }, span)); 370 | self.namespaces[ns].values.insert(sym, id); 371 | id 372 | } 373 | 374 | /// Unbind a value, replacing it's currently defined scheme with 375 | /// Scheme::Mono('a), where 'a is some fresh type variable 376 | /// 377 | /// # Panics 378 | /// 379 | /// This will panic if `sym` is not defined in the current namespace 380 | /// tree 381 | fn unbind_value(&mut self, sym: Symbol) { 382 | let id = self.namespaces[self.current] 383 | .values 384 | .get(&sym) 385 | .expect("error: redefine_value"); 386 | let s = Scheme::Mono(self.fresh_tyvar()); 387 | 388 | let _ = std::mem::replace(&mut self.values[id.0 as usize].data.scheme, s); 389 | } 390 | 391 | /// Starting from the current [`Namespace`], search for a bound name. 392 | /// If it's not found, then recursively search parent namespaces 393 | fn lookup_infix(&self, s: &Symbol) -> Option { 394 | let mut ptr = &self.namespaces[self.current]; 395 | loop { 396 | match ptr.infix.get(s) { 397 | Some(idx) => return Some(*idx), 398 | None => ptr = &self.namespaces[ptr.parent?], 399 | } 400 | } 401 | } 402 | 403 | /// Return the index of a symbol into the global type definition vector 404 | fn lookup_type_id(&self, sym: &Symbol) -> Option { 405 | let mut ptr = &self.namespaces[self.current]; 406 | loop { 407 | match ptr.types.get(sym) { 408 | Some(idx) => return Some(*idx), 409 | None => ptr = &self.namespaces[ptr.parent?], 410 | } 411 | } 412 | } 413 | 414 | fn lookup_type(&self, sym: &Symbol) -> Option<&TypeStructure<'ar>> { 415 | Some(&self.types[self.lookup_type_id(sym)?.0 as usize]) 416 | } 417 | 418 | fn lookup_value(&self, sym: &Symbol) -> Option<&Spanned>> { 419 | let mut ptr = &self.namespaces[self.current]; 420 | loop { 421 | match ptr.values.get(sym) { 422 | Some(idx) => return self.values.get(idx.0 as usize), 423 | None => ptr = &self.namespaces[ptr.parent?], 424 | } 425 | } 426 | } 427 | 428 | fn lookup_tyvar(&mut self, s: &Symbol, allow_unbound: bool) -> Option<&'ar TypeVar<'ar>> { 429 | for (sym, tv) in self.tyvars.iter().rev() { 430 | if sym == s { 431 | return Some(tv); 432 | } 433 | } 434 | if allow_unbound { 435 | let v = self.arena.fresh_type_var(self.tyvar_rank); 436 | self.tyvars.push((*s, v)); 437 | Some(v) 438 | } else { 439 | None 440 | } 441 | } 442 | 443 | fn fresh_tyvar(&self) -> &'ar Type<'ar> { 444 | self.arena.fresh_var(self.tyvar_rank) 445 | } 446 | 447 | fn fresh_var(&self) -> Symbol { 448 | let n = self.gensym.get(); 449 | let s = Symbol::Gensym(n as u32); 450 | self.gensym.set(n + 1); 451 | s 452 | } 453 | 454 | fn const_ty(&self, c: &ast::Const) -> &'ar Type<'ar> { 455 | match c { 456 | ast::Const::Char(_) => self.arena.char(), 457 | ast::Const::Int(_) => self.arena.int(), 458 | ast::Const::String(_) => self.arena.string(), 459 | ast::Const::Unit => self.arena.unit(), 460 | } 461 | } 462 | 463 | /// Generic function to elaborate an ast::Row into a core::Row 464 | /// where T might be ast::Type and S is core::Type, for instance 465 | fn elab_row, &T) -> S>( 466 | &mut self, 467 | mut f: F, 468 | row: &ast::Row, 469 | ) -> Row { 470 | Row { 471 | label: row.label, 472 | span: row.span, 473 | data: f(self, &row.data), 474 | } 475 | } 476 | } 477 | 478 | impl<'ar> Database<'ar> { 479 | /// Note that this can only be called once per type variable! 480 | fn bind(&mut self, var: &'ar TypeVar<'ar>, ty: &'ar Type<'ar>, f: &F) 481 | where 482 | F: Fn() -> CantUnify<'ar>, 483 | { 484 | if let Type::Var(v2) = ty { 485 | // TODO: Ensure that testing on id alone is ok - I believe it should be 486 | if v2.id == var.id { 487 | return; 488 | } 489 | } 490 | if ty.occurs_check(var) { 491 | let err = f().add_reason("Cyclic type detected"); 492 | self.unification_errors.push(err); 493 | } else { 494 | // Move into else block, so that even if occurs check fails, we can 495 | // proceed with type checking without creating a cycle 496 | var.data.set(Some(ty)); 497 | } 498 | } 499 | 500 | fn one_flex( 501 | &mut self, 502 | rigid: &SortedRecord<&'ar Type<'ar>>, 503 | flex: &Flex<'ar>, 504 | ty1: &'ar Type<'ar>, 505 | ty2: &'ar Type<'ar>, 506 | f: &F, 507 | ) where 508 | F: Fn(CantUnify<'ar>) -> CantUnify<'ar>, 509 | { 510 | let mut merge = Vec::new(); 511 | for field in flex.known.iter() { 512 | match rigid.contains(&field.label) { 513 | Some(row) => { 514 | // self.unify(&field.data, &row.data, &|c| { 515 | // f(c.add_reason("Record types have identical fields with differing types") 516 | // .add_spans(field.span, row.span)) 517 | // }); 518 | self.unify(&field.data, &row.data, f); 519 | } 520 | None => { 521 | let err = f(CantUnify::new(ty1, ty2)) 522 | .add_reason("Record types have differing number of fields"); 523 | self.unification_errors.push(err); 524 | return; 525 | } 526 | } 527 | } 528 | 529 | // Create a list of row types that `flex` needs 530 | for field in rigid.iter() { 531 | if flex.known.contains(&field.label).is_none() { 532 | merge.push(*field); 533 | } 534 | } 535 | 536 | let mut borrow = flex.unknown.borrow_mut(); 537 | *borrow = Some(SortedRecord::new_unchecked(merge)); 538 | } 539 | 540 | fn unify_records( 541 | &mut self, 542 | r1: &SortedRecord<&'ar Type<'ar>>, 543 | r2: &SortedRecord<&'ar Type<'ar>>, 544 | ty1: &'ar Type<'ar>, 545 | ty2: &'ar Type<'ar>, 546 | f: &F, 547 | ) where 548 | F: Fn(CantUnify<'ar>) -> CantUnify<'ar>, 549 | { 550 | if r1.len() != r2.len() { 551 | let err = f(CantUnify::new(ty1, ty2)) 552 | .add_reason("Record types have differing number of fields"); 553 | self.unification_errors.push(err); 554 | return; 555 | } 556 | 557 | for (ra, rb) in r1.iter().zip(r2.iter()) { 558 | if ra.label != rb.label { 559 | let err = f(CantUnify::new(&ra.data, &rb.data)) 560 | .add_reason("Record types have identical fields with differing types") 561 | .add_spans(ra.span, rb.span); 562 | self.unification_errors.push(err); 563 | return; 564 | } 565 | self.unify(&ra.data, &rb.data, f); 566 | } 567 | } 568 | 569 | pub fn unify(&mut self, a: &'ar Type<'ar>, b: &'ar Type<'ar>, f: &F) 570 | where 571 | F: Fn(CantUnify<'ar>) -> CantUnify<'ar>, 572 | { 573 | match (a, b) { 574 | (Type::Var(a1), Type::Var(b1)) => match (a1.ty(), b1.ty()) { 575 | (Some(a), Some(b)) => self.unify(a, b, f), 576 | (Some(a), None) => self.unify(a, b, f), 577 | (None, Some(b)) => self.unify(a, b, f), 578 | (None, None) => self.bind(a1, b, &|| f(CantUnify::new(a, b))), 579 | }, 580 | (Type::Var(a_var), b) => match a_var.ty() { 581 | Some(ty) => self.unify(ty, b, f), 582 | None => self.bind(a_var, b, &|| f(CantUnify::new(a, b))), 583 | }, 584 | (a, Type::Var(b_var)) => match b_var.ty() { 585 | Some(ty) => self.unify(a, ty, f), 586 | None => self.bind(b_var, a, &|| f(CantUnify::new(a, b))), 587 | }, 588 | (Type::Con(tc1, a_args), Type::Con(tc2, b_args)) => { 589 | if tc1 != tc2 { 590 | let err = f(CantUnify::new(a, b)).add_reason("Type constructors differ"); 591 | self.unification_errors.push(err); 592 | } else if a_args.len() != b_args.len() { 593 | let err = f(CantUnify::new(a, b)) 594 | .add_reason("Argument lengths to type constructors differ"); 595 | self.unification_errors.push(err); 596 | } else { 597 | for (c, d) in a_args.into_iter().zip(b_args) { 598 | self.unify(c, d, f); 599 | } 600 | } 601 | } 602 | (Type::Record(r1), Type::Record(r2)) => self.unify_records(r1, r2, a, b, f), 603 | (Type::Flex(flex), Type::Record(rec)) => match flex.to_rigid() { 604 | Some(r1) => self.unify_records(&r1, rec, a, b, f), 605 | None => self.one_flex(rec, flex, a, b, f), 606 | }, 607 | (Type::Record(rec), Type::Flex(flex)) => match flex.to_rigid() { 608 | Some(r1) => self.unify_records(&r1, rec, a, b, f), 609 | None => self.one_flex(rec, flex, a, b, f), 610 | }, 611 | (Type::Flex(f1), Type::Flex(f2)) => todo!(), 612 | (a, b) => { 613 | let err = f(CantUnify::new(a, b)).add_reason("Can't unify these types"); 614 | self.unification_errors.push(err); 615 | } 616 | } 617 | } 618 | 619 | pub fn unify_list(&mut self, sp: Span, tys: &[&'ar Type<'ar>]) { 620 | if tys.len() == 1 { 621 | return; 622 | } 623 | let fst = &tys[0]; 624 | for ty in tys { 625 | self.unify(ty, fst, &|c| { 626 | c.span(sp).add_message("List has items of differing types") 627 | }); 628 | } 629 | } 630 | 631 | pub fn generalize(&self, ty: &'ar Type<'ar>) -> Scheme<'ar> { 632 | let ftv = ty.ftv_rank(self.tyvar_rank); 633 | 634 | match ftv.len() { 635 | 0 => Scheme::Mono(ty), 636 | _ => Scheme::Poly(ftv, ty), 637 | } 638 | } 639 | 640 | pub fn instantiate(&self, scheme: &Scheme<'ar>) -> &'ar Type<'ar> { 641 | match scheme { 642 | Scheme::Mono(ty) => ty, 643 | Scheme::Poly(vars, ty) => { 644 | let map = vars.into_iter().map(|v| (*v, self.fresh_tyvar())).collect(); 645 | ty.apply(&self.arena, &map) 646 | } 647 | } 648 | } 649 | 650 | pub fn check_type_names(&mut self, sp: Span, ty: &'ar Type<'ar>) { 651 | let mut names = Vec::new(); 652 | ty.visit(|f| match f { 653 | Type::Con(tc, _) => names.push(*tc), 654 | _ => {} 655 | }); 656 | 657 | for tycon in names { 658 | if self.lookup_type(&tycon.name).is_none() { 659 | self.diags.push(Diagnostic::error( 660 | sp, 661 | format!("type {:?} escapes inner scope!", tycon.name), 662 | )); 663 | } 664 | } 665 | } 666 | 667 | pub fn walk_type(&mut self, ty: &ast::Type, allow_unbound: bool) -> &'ar Type<'ar> { 668 | use ast::TypeKind::*; 669 | match &ty.data { 670 | Var(s) => match self.lookup_tyvar(s, allow_unbound) { 671 | Some(tv) => self.arena.alloc(Type::Var(tv)), 672 | None => { 673 | self.diags.push(Diagnostic::error( 674 | ty.span, 675 | format!("unbound type variable {:?}", s), 676 | )); 677 | self.fresh_tyvar() 678 | } 679 | }, 680 | Con(s, args) => { 681 | let args = args 682 | .iter() 683 | .map(|ty| self.walk_type(&ty, allow_unbound)) 684 | .collect::>(); 685 | 686 | let con = match self.lookup_type(s) { 687 | Some(t) => t.clone(), 688 | None => { 689 | self.diags.push(Diagnostic::error( 690 | ty.span, 691 | format!("unbound type variable {:?}", s), 692 | )); 693 | 694 | TypeStructure::Tycon(Tycon { 695 | name: self.fresh_var(), 696 | arity: args.len(), 697 | }) 698 | } 699 | }; 700 | 701 | if con.arity() != args.len() { 702 | self.diags.push( 703 | Diagnostic::error( 704 | ty.span, 705 | format!( 706 | "type constructor requires {} arguments, but {} are supplied", 707 | con.arity(), 708 | args.len() 709 | ), 710 | ) 711 | .message(ty.span, format!("in type {:?}", ty)), 712 | ); 713 | } 714 | con.apply(&self.arena, args) 715 | } 716 | Record(rows) => self.arena.alloc(Type::Record(SortedRecord::new( 717 | rows.into_iter() 718 | .map(|row| self.elab_row(|f, r| f.walk_type(r, allow_unbound), row)) 719 | .collect::>>(), 720 | ))), 721 | } 722 | } 723 | } 724 | 725 | impl<'ar> Database<'ar> { 726 | pub fn walk_pat( 727 | &mut self, 728 | pat: &ast::Pat, 729 | bind: bool, 730 | ) -> (&'ar Type<'ar>, Vec<(Spanned, &'ar Type<'ar>)>) { 731 | let mut bindings = Vec::new(); 732 | let ty = self.walk_pat_inner(pat, bind, &mut bindings); 733 | (ty, bindings) 734 | } 735 | 736 | pub(crate) fn walk_pat_inner( 737 | &mut self, 738 | pat: &ast::Pat, 739 | bind: bool, 740 | bindings: &mut Vec<(Spanned, &'ar Type<'ar>)>, 741 | ) -> &'ar Type<'ar> { 742 | use ast::PatKind::*; 743 | match &pat.data { 744 | App(con, p) => { 745 | let arg_ty = self.walk_pat_inner(p, bind, bindings); 746 | match self.lookup_value(con).cloned() { 747 | Some(Spanned { 748 | data: 749 | ValueStructure { 750 | scheme, 751 | status: IdStatus::Con(_), 752 | }, 753 | span, 754 | }) => { 755 | let inst = self.instantiate(&scheme); 756 | 757 | let (arg, res) = match inst.de_arrow() { 758 | Some((a, r)) => (a, r), 759 | None => { 760 | let (dom, rng) = (self.fresh_tyvar(), self.fresh_tyvar()); 761 | let arr = self.arena.arrow(dom, rng); 762 | self.unify(inst, arr, &|c| { 763 | c.span(pat.span).add_message( 764 | "expected pattern contructor to take arguments", 765 | ) 766 | }); 767 | (dom, rng) 768 | } 769 | }; 770 | self.unify(arg, arg_ty, &|c| { 771 | c.span(pat.span) 772 | .add_spans(p.span, span) 773 | .add_message("argument to constructor is the wrong type") 774 | }); 775 | self.bindings.push((pat.span, res)); 776 | res 777 | } 778 | _ => { 779 | self.diags.push(Diagnostic::error( 780 | pat.span, 781 | format!("Non-constructor {:?} applied to pattern", con), 782 | )); 783 | let ty = self.arena.fresh_var(self.tyvar_rank); 784 | self.bindings.push((pat.span, ty)); 785 | ty 786 | } 787 | } 788 | } 789 | Ascribe(p, ty) => { 790 | let ty1 = self.walk_pat_inner(p, bind, bindings); 791 | let ty2 = self.walk_type(ty, true); 792 | self.unify(ty1, ty2, &|c| { 793 | c.span(pat.span) 794 | .add_spans(p.span, ty.span) 795 | .add_message("pattern type and ascribed type differ") 796 | }); 797 | self.bindings.push((pat.span, ty2)); 798 | ty2 799 | } 800 | Const(c) => self.const_ty(c), 801 | FlatApp(pats) => { 802 | let p = match self.pat_precedence(pats.clone()) { 803 | Ok(p) => p, 804 | Err(err) => { 805 | match err { 806 | precedence::Error::EndsInfix => self.diags.push(Diagnostic::error( 807 | pat.span, 808 | "application pattern ends with an infix operator", 809 | )), 810 | precedence::Error::InfixInPrefix => self.diags.push(Diagnostic::error( 811 | pat.span, 812 | "application pattern starts with an infix operator", 813 | )), 814 | precedence::Error::SamePrecedence => { 815 | self.diags.push(Diagnostic::error( 816 | pat.span, 817 | "application pattern mixes operators of equal precedence", 818 | )) 819 | } 820 | precedence::Error::InvalidOperator => { 821 | self.diags.push(Diagnostic::error( 822 | pat.span, 823 | "application pattern doesn't contain infix operator", 824 | )) 825 | } 826 | } 827 | 828 | // attempt error recovery 829 | ast::Pat::new(ast::PatKind::Wild, pat.span) 830 | } 831 | }; 832 | let ty = self.walk_pat_inner(&p, bind, bindings); 833 | self.bindings.push((pat.span, ty)); 834 | ty 835 | } 836 | List(pats) => { 837 | let tys = pats 838 | .into_iter() 839 | .map(|p| self.walk_pat_inner(p, bind, bindings)) 840 | .collect::>(); 841 | 842 | self.unify_list(pat.span, &tys); 843 | let ty = self.arena.list(tys[0]); 844 | self.bindings.push((pat.span, ty)); 845 | ty 846 | } 847 | Record(rows, flex) => { 848 | let tys = rows 849 | .iter() 850 | .map(|p| Row { 851 | label: p.label, 852 | span: p.span, 853 | data: self.walk_pat_inner(&p.data, bind, bindings), 854 | }) 855 | .collect::>>(); 856 | 857 | let ty = match flex { 858 | false => self.arena.alloc(Type::Record(SortedRecord::new(tys))), 859 | true => self 860 | .arena 861 | .alloc(Type::Flex(Flex::new(SortedRecord::new(tys)))), 862 | }; 863 | self.bindings.push((pat.span, ty)); 864 | ty 865 | } 866 | Variable(sym) => match self.lookup_value(sym) { 867 | // Rule 35 868 | Some(Spanned { 869 | data: 870 | ValueStructure { 871 | scheme, 872 | status: IdStatus::Exn(_), 873 | }, 874 | .. 875 | }) 876 | | Some(Spanned { 877 | data: 878 | ValueStructure { 879 | scheme, 880 | status: IdStatus::Con(_), 881 | }, 882 | .. 883 | }) => self.instantiate(scheme), 884 | _ => { 885 | // Rule 34 886 | // let tvar = self.arena.fresh_type_var(self.tyvar_rank); 887 | let ty = self.fresh_tyvar(); 888 | if bind { 889 | self.define_value(*sym, Scheme::Mono(ty), IdStatus::Var, pat.span); 890 | } 891 | bindings.push((Spanned::new(*sym, pat.span), ty)); 892 | self.bindings.push((pat.span, ty)); 893 | ty 894 | } 895 | }, 896 | Wild => { 897 | let ty = self.fresh_tyvar(); 898 | self.bindings.push((pat.span, ty)); 899 | ty 900 | } 901 | } 902 | } 903 | } 904 | 905 | type Rule<'ar> = (&'ar Type<'ar>, &'ar Type<'ar>); 906 | impl<'ar> Database<'ar> { 907 | fn elab_rule(&mut self, rule: &ast::Rule, bind: bool) -> Rule<'ar> { 908 | let (pat, _) = self.walk_pat(&rule.pat, bind); 909 | let expr = self.walk_expr(&rule.expr); 910 | (pat, expr) 911 | } 912 | 913 | pub fn elab_rules( 914 | &mut self, 915 | sp: Span, 916 | rules: &[ast::Rule], 917 | ) -> (Vec>, &'ar Type<'ar>) { 918 | self.with_scope(|ctx| { 919 | let rules = rules 920 | .into_iter() 921 | .map(|r| ctx.elab_rule(r, true)) 922 | .collect::>(); 923 | 924 | let mut rtys = rules 925 | .iter() 926 | .map(|(p, e)| ctx.arena.arrow(p, e)) 927 | .collect::>(); 928 | 929 | ctx.unify_list(sp, &rtys); 930 | let fst = rtys.remove(0); 931 | (rules, fst) 932 | }) 933 | } 934 | 935 | pub fn walk_expr(&mut self, expr: &ast::Expr) -> &'ar Type<'ar> { 936 | match &expr.data { 937 | ast::ExprKind::Andalso(e1, e2) => { 938 | let ty1 = self.walk_expr(e1); 939 | let ty2 = self.walk_expr(e2); 940 | self.unify(ty1, self.arena.bool(), &|c| { 941 | c.span(e1.span) 942 | .add_message("expected bool expression in `andalso`") 943 | }); 944 | self.unify(ty2, self.arena.bool(), &|c| { 945 | c.span(e2.span) 946 | .add_message("expected bool expression in `andalso`") 947 | }); 948 | self.bindings.push((expr.span, ty1)); 949 | ty1 950 | } 951 | ast::ExprKind::App(e1, e2) => { 952 | let ty1 = self.walk_expr(e1); 953 | let ty2 = self.walk_expr(e2); 954 | 955 | let f = self.fresh_tyvar(); 956 | self.unify(ty1, self.arena.arrow(ty2, f), &|c| { 957 | c.span(e1.span).add_message("incorrect function arguments") 958 | }); 959 | self.bindings.push((expr.span, f)); 960 | f 961 | } 962 | ast::ExprKind::Case(scrutinee, rules) => { 963 | let casee = self.walk_expr(scrutinee); 964 | 965 | let (_, ty) = self.elab_rules(expr.span, rules); 966 | 967 | let (arg, res) = match ty.de_arrow() { 968 | Some((a, r)) => (a, r), 969 | None => { 970 | let (dom, rng) = (self.fresh_tyvar(), self.fresh_tyvar()); 971 | let arr = self.arena.arrow(dom, rng); 972 | self.unify(ty, arr, &|c| { 973 | c.span(expr.span).add_message("mistyped match rule") 974 | }); 975 | (dom, rng) 976 | } 977 | }; 978 | 979 | self.unify(casee, arg, &|c| { 980 | c.span(scrutinee.span) 981 | .add_message("`case` expression and patterns don't have the same type") 982 | }); 983 | self.bindings.push((expr.span, res)); 984 | res 985 | } 986 | ast::ExprKind::Const(c) => { 987 | let ty = self.const_ty(c); 988 | self.bindings.push((expr.span, ty)); 989 | ty 990 | } 991 | ast::ExprKind::Constraint(ex, ty) => { 992 | let ty1 = self.walk_expr(ex); 993 | let ty2 = self.walk_type(ty, false); 994 | self.unify(ty1, ty2, &|c| { 995 | c.span(expr.span) 996 | .add_message("expression type and type constraint differ") 997 | }); 998 | self.bindings.push((expr.span, ty1)); 999 | ty1 1000 | } 1001 | ast::ExprKind::FlatApp(exprs) => { 1002 | let p = match self.expr_precedence(exprs.clone()) { 1003 | Ok(p) => p, 1004 | Err(err) => { 1005 | match err { 1006 | precedence::Error::EndsInfix => self.diags.push(Diagnostic::error( 1007 | expr.span, 1008 | "application expr ends with an infix operator", 1009 | )), 1010 | precedence::Error::InfixInPrefix => self.diags.push(Diagnostic::error( 1011 | expr.span, 1012 | "application expr starts with an infix operator", 1013 | )), 1014 | precedence::Error::SamePrecedence => { 1015 | self.diags.push(Diagnostic::error( 1016 | expr.span, 1017 | "application expr mixes operators of equal precedence", 1018 | )) 1019 | } 1020 | precedence::Error::InvalidOperator => { 1021 | self.diags.push(Diagnostic::error( 1022 | expr.span, 1023 | "application expr doesn't contain infix operator", 1024 | )) 1025 | } 1026 | } 1027 | // Return a dummy variable so that we can continue elaboration 1028 | ast::Expr::new(ast::ExprKind::Var(self.fresh_var()), Span::dummy()) 1029 | } 1030 | }; 1031 | let ty = self.walk_expr(&p); 1032 | self.bindings.push((expr.span, ty)); 1033 | ty 1034 | } 1035 | ast::ExprKind::Fn(rules) => { 1036 | let (_, ty) = self.elab_rules(expr.span, rules); 1037 | self.bindings.push((expr.span, ty)); 1038 | ty 1039 | } 1040 | ast::ExprKind::Handle(ex, rules) => { 1041 | let ex = self.walk_expr(ex); 1042 | let (_, ty) = self.elab_rules(expr.span, rules); 1043 | 1044 | let (arg, res) = match ty.de_arrow() { 1045 | Some((a, r)) => (a, r), 1046 | None => { 1047 | let (dom, rng) = (self.fresh_tyvar(), self.fresh_tyvar()); 1048 | let arr = self.arena.arrow(dom, rng); 1049 | self.unify(ty, arr, &|c| { 1050 | c.span(expr.span).add_message("mistyped match rule") 1051 | }); 1052 | (dom, rng) 1053 | } 1054 | }; 1055 | 1056 | self.unify(ex, res, &|c| { 1057 | c.span(expr.span) 1058 | .add_message("mismatch in return type of `handle`") 1059 | }); 1060 | self.unify(arg, self.arena.exn(), &|c| { 1061 | c.span(expr.span) 1062 | .add_message("non-exception in `handle` rule") 1063 | }); 1064 | self.bindings.push((expr.span, res)); 1065 | res 1066 | } 1067 | ast::ExprKind::If(e1, e2, e3) => { 1068 | let ty1 = self.walk_expr(e1); 1069 | let ty2 = self.walk_expr(e2); 1070 | let ty3 = self.walk_expr(e3); 1071 | self.unify(ty1, self.arena.bool(), &|c| { 1072 | c.span(e1.span) 1073 | .add_message("expected bool expression in `if`") 1074 | }); 1075 | self.unify(ty2, ty3, &|c| { 1076 | c.span(expr.span) 1077 | .add_spans(e2.span, e3.span) 1078 | .add_message("`if` arms don't have the same type") 1079 | }); 1080 | self.bindings.push((expr.span, ty2)); 1081 | ty2 1082 | } 1083 | ast::ExprKind::Let(decls, body) => { 1084 | let ty = self.with_scope(|ctx| { 1085 | for decl in decls { 1086 | ctx.walk_decl(decl); 1087 | } 1088 | ctx.walk_expr(body) 1089 | }); 1090 | self.check_type_names(body.span, ty); 1091 | self.bindings.push((expr.span, ty)); 1092 | ty 1093 | } 1094 | ast::ExprKind::List(exprs) => { 1095 | let exprs = exprs 1096 | .into_iter() 1097 | .map(|ex| self.walk_expr(ex)) 1098 | .collect::>(); 1099 | self.unify_list(expr.span, &exprs); 1100 | // Pick the first type, since that was what everything was unified against 1101 | let ty = self.arena.list(exprs[0]); 1102 | self.bindings.push((expr.span, ty)); 1103 | ty 1104 | } 1105 | ast::ExprKind::Orelse(e1, e2) => { 1106 | let ty1 = self.walk_expr(e1); 1107 | let ty2 = self.walk_expr(e2); 1108 | self.unify(ty1, self.arena.bool(), &|c| { 1109 | c.span(e1.span) 1110 | .add_message("expected bool expression in `orelse`") 1111 | }); 1112 | self.unify(ty2, self.arena.bool(), &|c| { 1113 | c.span(e2.span) 1114 | .add_message("expected bool expression in `orelse`") 1115 | }); 1116 | self.bindings.push((expr.span, ty1)); 1117 | ty1 1118 | } 1119 | ast::ExprKind::Primitive(prim) => { 1120 | // let name = prim.sym; 1121 | let ty = self.walk_type(&prim.ty, false); 1122 | self.bindings.push((expr.span, ty)); 1123 | ty 1124 | } 1125 | ast::ExprKind::Raise(expr) => { 1126 | let ty = self.fresh_tyvar(); 1127 | let ex = self.walk_expr(expr); 1128 | self.unify(ex, self.arena.exn(), &|c| { 1129 | c.span(expr.span) 1130 | .add_message("can't `raise` a non-exception type") 1131 | }); 1132 | self.bindings.push((expr.span, ty)); 1133 | ty 1134 | } 1135 | ast::ExprKind::Record(rows) => { 1136 | let tys = rows 1137 | .into_iter() 1138 | .map(|r| self.elab_row(|ec, r| ec.walk_expr(r), r)) 1139 | .collect::>>>(); 1140 | 1141 | let ty = self.arena.alloc(Type::Record(SortedRecord::new(tys))); 1142 | self.bindings.push((expr.span, ty)); 1143 | ty 1144 | } 1145 | ast::ExprKind::Selector(s) => { 1146 | // FIXME 1147 | 1148 | let row = ast::Row { 1149 | label: *s, 1150 | data: ast::Pat::new(ast::PatKind::Variable(*s), Span::dummy()), 1151 | span: Span::dummy(), 1152 | }; 1153 | let pat = ast::Pat::new(ast::PatKind::Record(vec![row], true), Span::dummy()); 1154 | let inner = ast::Expr::new(ast::ExprKind::Var(*s), Span::dummy()); 1155 | let ty = self.walk_expr(&ast::Expr::new( 1156 | ast::ExprKind::Fn(vec![ast::Rule { 1157 | pat, 1158 | expr: inner, 1159 | span: expr.span, 1160 | }]), 1161 | expr.span, 1162 | )); 1163 | self.bindings.push((expr.span, ty)); 1164 | ty 1165 | } 1166 | ast::ExprKind::Seq(exprs) => { 1167 | let mut ty = self.arena.unit(); 1168 | for (idx, ex) in exprs.iter().enumerate() { 1169 | if idx != exprs.len() - 1 { 1170 | let ety = self.walk_expr(ex); 1171 | self.unify(ety, ty, &|c| { 1172 | c.span(ex.span) 1173 | .add_message("expressions in sequence must return `unit`") 1174 | }); 1175 | } else { 1176 | ty = self.walk_expr(ex); 1177 | } 1178 | } 1179 | self.bindings.push((expr.span, ty)); 1180 | ty 1181 | } 1182 | ast::ExprKind::Var(sym) => match self.lookup_value(sym) { 1183 | Some(spanned) => { 1184 | let ty = self.instantiate(&spanned.data.scheme); 1185 | self.bindings.push((expr.span, ty)); 1186 | self.references.push((expr.span, *sym)); 1187 | ty 1188 | } 1189 | None => { 1190 | self.diags.push(Diagnostic::error( 1191 | expr.span, 1192 | format!("unbound variable {:?}", sym), 1193 | )); 1194 | let ty = self.fresh_tyvar(); 1195 | self.bindings.push((expr.span, ty)); 1196 | ty 1197 | } 1198 | }, 1199 | _ => panic!(Diagnostic::error( 1200 | expr.span, 1201 | format!("unknown expr {:?}", expr), 1202 | )), 1203 | } 1204 | } 1205 | } 1206 | 1207 | impl<'ar> Database<'ar> { 1208 | fn elab_decl_fixity(&mut self, fixity: &ast::Fixity, bp: u8, sym: Symbol) { 1209 | let fix = match fixity { 1210 | ast::Fixity::Infix => Fixity::Infix(bp, bp + 1), 1211 | ast::Fixity::Infixr => Fixity::Infix(bp + 1, bp), 1212 | ast::Fixity::Nonfix => Fixity::Nonfix, 1213 | }; 1214 | self.namespaces[self.current].infix.insert(sym, fix); 1215 | } 1216 | 1217 | fn elab_decl_type(&mut self, tbs: &[ast::Typebind]) { 1218 | for typebind in tbs { 1219 | let scheme = if !typebind.tyvars.is_empty() { 1220 | self.with_tyvars(|ctx| { 1221 | for s in typebind.tyvars.iter() { 1222 | let v = ctx.arena.fresh_type_var(ctx.tyvar_rank); 1223 | ctx.tyvars.push((*s, v)); 1224 | } 1225 | let ty = ctx.walk_type(&typebind.ty, false); 1226 | let s = match typebind.tyvars.len() { 1227 | 0 => Scheme::Mono(ty), 1228 | _ => Scheme::Poly( 1229 | typebind 1230 | .tyvars 1231 | .iter() 1232 | .map(|tv| ctx.lookup_tyvar(tv, false).unwrap().id) 1233 | .collect(), 1234 | ty, 1235 | ), 1236 | }; 1237 | 1238 | s 1239 | }) 1240 | } else { 1241 | Scheme::Mono(self.walk_type(&typebind.ty, false)) 1242 | }; 1243 | self.define_type( 1244 | typebind.tycon, 1245 | TypeStructure::Scheme(scheme), 1246 | typebind.ty.span, 1247 | ); 1248 | } 1249 | } 1250 | 1251 | fn elab_decl_conbind(&mut self, db: &ast::Datatype) { 1252 | let tycon = Tycon::new(db.tycon, db.tyvars.len()); 1253 | 1254 | // This is safe to unwrap, because we already bound it. 1255 | let type_id = self.lookup_type_id(&db.tycon).unwrap(); 1256 | 1257 | // Should be safe to unwrap here as well, since the caller has bound db.tyvars 1258 | let tyvars: Vec<&'ar TypeVar<'ar>> = db 1259 | .tyvars 1260 | .iter() 1261 | .map(|sym| self.lookup_tyvar(sym, false).unwrap()) 1262 | .collect(); 1263 | 1264 | let mut constructors = Vec::new(); 1265 | for (tag, con) in db.constructors.iter().enumerate() { 1266 | if self.lookup_value(&con.label).is_some() { 1267 | self.diags.push(Diagnostic::warn( 1268 | con.span, 1269 | format!("rebinding of data constructor {:?}", con.label), 1270 | )); 1271 | return; 1272 | } 1273 | 1274 | let cons = Constructor { 1275 | name: con.label, 1276 | type_id, 1277 | tag: tag as u8, 1278 | arity: con.data.is_some() as u8, 1279 | type_arity: db.constructors.len() as u8, 1280 | }; 1281 | 1282 | let res = self.arena.alloc(Type::Con( 1283 | tycon, 1284 | tyvars 1285 | .iter() 1286 | .map(|v| &*self.arena.alloc(Type::Var(v))) 1287 | .collect(), 1288 | )); 1289 | 1290 | let ty = match &con.data { 1291 | Some(ty) => { 1292 | let dom = self.walk_type(ty, false); 1293 | constructors.push((cons, Some(dom))); 1294 | self.arena.arrow(dom, res) 1295 | } 1296 | None => { 1297 | constructors.push((cons, None)); 1298 | res 1299 | } 1300 | }; 1301 | 1302 | // calling `generalize` here will actually introduce some bugs, since 1303 | // any type vars could've already been placed in the VE, thereby 1304 | // preventing later constructors containing the same tyvars from 1305 | // being properly generalized 1306 | let s = match tyvars.len() { 1307 | 0 => Scheme::Mono(ty), 1308 | _ => Scheme::Poly(tyvars.iter().map(|tv| tv.id).collect(), ty), 1309 | }; 1310 | self.define_value(con.label, s, IdStatus::Con(cons), con.span); 1311 | } 1312 | } 1313 | 1314 | fn elab_decl_datatype(&mut self, dbs: &[ast::Datatype]) { 1315 | // Add all of the type constructors to the environment first, so that 1316 | // we can construct data constructor arguments (e.g. recursive/mutually 1317 | // recursive datatypes) 1318 | for db in dbs { 1319 | let tycon = Tycon::new(db.tycon, db.tyvars.len()); 1320 | self.define_type(db.tycon, TypeStructure::Tycon(tycon), db.span); 1321 | } 1322 | for db in dbs { 1323 | self.with_tyvars(|ctx| { 1324 | for s in &db.tyvars { 1325 | let v = ctx.arena.fresh_type_var(ctx.tyvar_rank); 1326 | ctx.tyvars.push((*s, v)); 1327 | } 1328 | ctx.elab_decl_conbind(db) 1329 | }); 1330 | } 1331 | } 1332 | 1333 | fn elab_decl_exception(&mut self, exns: &[ast::Variant]) { 1334 | for exn in exns { 1335 | let con = Constructor { 1336 | name: exn.label, 1337 | type_id: TypeId(8), 1338 | tag: 0, 1339 | arity: exn.data.is_some() as u8, 1340 | type_arity: exns.len() as u8, 1341 | }; 1342 | 1343 | match &exn.data { 1344 | Some(ty) => { 1345 | let ty = self.walk_type(ty, false); 1346 | self.define_value( 1347 | exn.label, 1348 | Scheme::Mono(self.arena.arrow(ty, self.arena.exn())), 1349 | IdStatus::Exn(con), 1350 | exn.span, 1351 | ); 1352 | } 1353 | None => { 1354 | self.define_value( 1355 | exn.label, 1356 | Scheme::Mono(self.arena.exn()), 1357 | IdStatus::Exn(con), 1358 | exn.span, 1359 | ); 1360 | } 1361 | } 1362 | } 1363 | } 1364 | 1365 | /// Perform initial elaboration on a function binding, enough to build up an environment 1366 | fn elab_decl_fnbind_ty<'s>( 1367 | &mut self, 1368 | name: Symbol, 1369 | arity: usize, 1370 | fbs: &'s [ast::FnBinding], 1371 | ) -> PartialFun<'s, 'ar> { 1372 | let arg_tys = (0..arity) 1373 | .map(|_| self.fresh_tyvar()) 1374 | .collect::>>(); 1375 | let res_ty = self.fresh_tyvar(); 1376 | let mut clauses = Vec::new(); 1377 | 1378 | for clause in fbs { 1379 | if let Some(ty) = &clause.res_ty { 1380 | let t = self.walk_type(&ty, false); 1381 | self.unify(res_ty, t, &|c| { 1382 | c.span(ty.span) 1383 | .add_message("function clause with result constraint of different type") 1384 | }); 1385 | } 1386 | 1387 | let mut bindings = Vec::new(); 1388 | for (idx, pat) in clause.pats.iter().enumerate() { 1389 | if idx >= arity { 1390 | self.diags.push(Diagnostic::error( 1391 | pat.span, 1392 | "function clause with wrong number of arguments", 1393 | )); 1394 | continue; 1395 | } 1396 | let pat_ty = self.walk_pat_inner(pat, false, &mut bindings); 1397 | self.unify(&arg_tys[idx], pat_ty, &|c| { 1398 | c.span(pat.span) 1399 | .add_message("function clause with argument of different type") 1400 | }); 1401 | } 1402 | clauses.push(PartialFnBinding { 1403 | expr: &clause.expr, 1404 | bindings, 1405 | span: clause.span, 1406 | }) 1407 | } 1408 | 1409 | let ty = arg_tys 1410 | .iter() 1411 | .rev() 1412 | .fold(res_ty, |acc, arg| self.arena.arrow(arg, acc)); 1413 | 1414 | PartialFun { 1415 | name, 1416 | clauses, 1417 | res_ty, 1418 | ty, 1419 | } 1420 | } 1421 | 1422 | fn elab_decl_fnbind(&mut self, fun: PartialFun<'_, 'ar>) { 1423 | let PartialFun { 1424 | clauses, 1425 | res_ty, 1426 | name, 1427 | ty, 1428 | } = fun; 1429 | 1430 | let mut fun_span = clauses[0].span; 1431 | // Destructure so that we can move `bindings` into a closure 1432 | for PartialFnBinding { 1433 | expr, 1434 | bindings, 1435 | span, 1436 | } in clauses 1437 | { 1438 | // Make a new scope, in which we define the pattern bindings, and proceed 1439 | // to elaborate the body of the function clause 1440 | self.tyvar_rank += 1; 1441 | let expr = self.with_scope(move |ctx| { 1442 | for (var, tv) in bindings { 1443 | ctx.define_value(var.data, Scheme::Mono(tv), IdStatus::Var, var.span); 1444 | } 1445 | ctx.walk_expr(&expr) 1446 | }); 1447 | self.tyvar_rank -= 1; 1448 | // Unify function clause body with result type 1449 | self.unify(res_ty, expr, &|c| { 1450 | c.span(span) 1451 | .add_message("function clause returns a different type") 1452 | }); 1453 | fun_span += span; 1454 | } 1455 | 1456 | // Rebind with final type. Unbind first so that generalization happens properly 1457 | self.unbind_value(name); 1458 | let sch = self.generalize(ty); 1459 | self.define_value(name, sch, IdStatus::Var, fun_span); 1460 | } 1461 | 1462 | fn elab_decl_fun(&mut self, tyvars: &[Symbol], fbs: &[ast::Fun]) { 1463 | self.with_tyvars(|ctx| { 1464 | let mut vars = Vec::new(); 1465 | ctx.tyvar_rank += 1; 1466 | 1467 | // First step is to bind any syntactically bound type vars 1468 | // e.g. fun ('a, 'b) option_map .. 1469 | for sym in tyvars { 1470 | let f = ctx.arena.fresh_type_var(ctx.tyvar_rank + 1); 1471 | vars.push(f.id); 1472 | ctx.tyvars.push((*sym, f)); 1473 | } 1474 | 1475 | // Check to make sure all of the function clauses are consistent within each binding group 1476 | let mut info = Vec::new(); 1477 | for f in fbs { 1478 | let n = f[0].name; 1479 | let a = f[0].pats.len(); 1480 | 1481 | // Create an initial binding, and add it the value environment 1482 | let fns = ctx.elab_decl_fnbind_ty(n, a, f); 1483 | ctx.define_value(fns.name, Scheme::Mono(fns.ty), IdStatus::Var, f.span); 1484 | info.push(fns); 1485 | } 1486 | ctx.tyvar_rank -= 1; 1487 | 1488 | // Now perform actual elaboration, we've bound the name of the function to a temp variable 1489 | for fun in info { 1490 | ctx.elab_decl_fnbind(fun) 1491 | } 1492 | }) 1493 | } 1494 | 1495 | // TODO: Properly handle scoping 1496 | fn elab_decl_local(&mut self, decls: &ast::Decl, body: &ast::Decl) { 1497 | self.with_scope(|ctx| { 1498 | ctx.walk_decl(decls); 1499 | let prev = ctx.local; 1500 | ctx.local = true; 1501 | ctx.walk_decl(body); 1502 | ctx.local = prev; 1503 | }) 1504 | } 1505 | 1506 | fn elab_decl_val(&mut self, tyvars: &[Symbol], pat: &ast::Pat, expr: &ast::Expr) { 1507 | self.with_tyvars(|ctx| { 1508 | ctx.tyvar_rank += 1; 1509 | for tyvar in tyvars { 1510 | ctx.tyvars 1511 | .push((*tyvar, ctx.arena.fresh_type_var(ctx.tyvar_rank))); 1512 | } 1513 | 1514 | let expr_ty = ctx.walk_expr(expr); 1515 | let (pat_ty, bindings) = ctx.walk_pat(pat, false); 1516 | 1517 | ctx.tyvar_rank -= 1; 1518 | // let non_expansive = expr.non_expansive(); 1519 | // FIXME: add to sml_frontend::ast? 1520 | let non_expansive = true; 1521 | 1522 | ctx.unify(pat_ty, expr_ty, &|c| { 1523 | c.span(pat.span) 1524 | .add_message("pattern type and expression type differ") 1525 | }); 1526 | for (var, tv) in bindings { 1527 | let sch = match non_expansive { 1528 | true => ctx.generalize(tv), 1529 | false => Scheme::Mono(tv), 1530 | }; 1531 | ctx.define_value(var.data, sch, IdStatus::Var, var.span); 1532 | } 1533 | }) 1534 | } 1535 | 1536 | pub fn walk_decl(&mut self, decl: &ast::Decl) { 1537 | match &decl.data { 1538 | ast::DeclKind::Datatype(dbs) => self.elab_decl_datatype(dbs), 1539 | ast::DeclKind::Type(tbs) => self.elab_decl_type(tbs), 1540 | ast::DeclKind::Function(tyvars, fbs) => self.elab_decl_fun(tyvars, fbs), 1541 | ast::DeclKind::Value(tyvars, pat, expr) => self.elab_decl_val(tyvars, pat, expr), 1542 | ast::DeclKind::Exception(exns) => self.elab_decl_exception(exns), 1543 | ast::DeclKind::Fixity(fixity, bp, sym) => self.elab_decl_fixity(fixity, *bp, *sym), 1544 | ast::DeclKind::Local(decls, body) => self.elab_decl_local(decls, body), 1545 | ast::DeclKind::Seq(decls) => { 1546 | for d in decls { 1547 | self.walk_decl(d); 1548 | } 1549 | } 1550 | } 1551 | // Expand span 1552 | self.namespaces[self.current].span.end = decl.span.end; 1553 | } 1554 | } 1555 | 1556 | impl<'ar> Query for &Database<'ar> { 1557 | fn fixity(&self, t: &ast::Pat) -> Fixity { 1558 | match &t.data { 1559 | ast::PatKind::Variable(s) => self.lookup_infix(s).unwrap_or(Fixity::Nonfix), 1560 | _ => Fixity::Nonfix, 1561 | } 1562 | } 1563 | 1564 | fn infix(&self, a: ast::Pat, b: ast::Pat, c: ast::Pat) -> Result { 1565 | // We know `a` must be a symbol, since it has a Fixity! 1566 | match a.data { 1567 | ast::PatKind::Variable(s) => { 1568 | let sp_bc = b.span + c.span; 1569 | let sp = a.span + sp_bc; 1570 | let rec = ast::Pat::new(ast::make_record_pat(vec![b, c], false), sp_bc); 1571 | Ok(ast::Pat::new(ast::PatKind::App(s, Box::new(rec)), sp)) 1572 | } 1573 | _ => Err(precedence::Error::InvalidOperator), 1574 | } 1575 | } 1576 | 1577 | fn apply(&self, a: ast::Pat, b: ast::Pat) -> Result { 1578 | match a.data { 1579 | ast::PatKind::Variable(s) => { 1580 | let sp = a.span + b.span; 1581 | Ok(ast::Pat::new(ast::PatKind::App(s, Box::new(b)), sp)) 1582 | } 1583 | _ => Err(precedence::Error::InvalidOperator), 1584 | } 1585 | } 1586 | } 1587 | 1588 | impl<'ar> Query for &Database<'ar> { 1589 | fn fixity(&self, t: &ast::Expr) -> Fixity { 1590 | match &t.data { 1591 | ast::ExprKind::Var(s) => self.lookup_infix(s).unwrap_or(Fixity::Nonfix), 1592 | _ => Fixity::Nonfix, 1593 | } 1594 | } 1595 | 1596 | fn infix( 1597 | &self, 1598 | a: ast::Expr, 1599 | b: ast::Expr, 1600 | c: ast::Expr, 1601 | ) -> Result { 1602 | let sp_bc = b.span + c.span; 1603 | let sp = a.span + sp_bc; 1604 | let rec = ast::Expr::new(ast::make_record(vec![b, c]), sp_bc); 1605 | Ok(ast::Expr::new( 1606 | ast::ExprKind::App(Box::new(a), Box::new(rec)), 1607 | sp, 1608 | )) 1609 | } 1610 | fn apply(&self, a: ast::Expr, b: ast::Expr) -> Result { 1611 | let sp = a.span + b.span; 1612 | Ok(ast::Expr::new( 1613 | ast::ExprKind::App(Box::new(a), Box::new(b)), 1614 | sp, 1615 | )) 1616 | } 1617 | } 1618 | 1619 | impl<'ar> Database<'ar> { 1620 | pub(crate) fn expr_precedence( 1621 | &self, 1622 | exprs: Vec, 1623 | ) -> Result { 1624 | Precedence::run(self, exprs) 1625 | } 1626 | 1627 | pub(crate) fn pat_precedence( 1628 | &self, 1629 | exprs: Vec, 1630 | ) -> Result { 1631 | Precedence::run(self, exprs) 1632 | } 1633 | } 1634 | -------------------------------------------------------------------------------- /crates/database/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod arena; 2 | pub mod builtin; 3 | pub mod check; 4 | pub mod database; 5 | pub mod types; 6 | 7 | use sml_util::interner::Symbol; 8 | use sml_util::span::{Location, Span, Spanned}; 9 | pub use types::*; 10 | 11 | pub use check::Check; 12 | pub use database::{CantUnify, Database}; 13 | 14 | #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Hash)] 15 | pub struct TypeId(pub u32); 16 | 17 | #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Hash)] 18 | pub struct ExprId(pub u32); 19 | 20 | #[derive(Clone)] 21 | pub struct Datatype<'ar> { 22 | pub tycon: Tycon, 23 | pub tyvars: Vec, 24 | pub constructors: Vec<(Constructor, Option<&'ar Type<'ar>>)>, 25 | } 26 | 27 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] 28 | pub struct Row { 29 | pub label: Symbol, 30 | pub data: T, 31 | pub span: Span, 32 | } 33 | 34 | pub struct SortedRecord { 35 | pub rows: Vec>, 36 | } 37 | 38 | impl SortedRecord { 39 | pub fn new(mut rows: Vec>) -> SortedRecord { 40 | rows.sort_by(|a, b| a.label.cmp(&b.label)); 41 | SortedRecord { rows } 42 | } 43 | 44 | pub fn new_unchecked(rows: Vec>) -> SortedRecord { 45 | SortedRecord { rows } 46 | } 47 | 48 | pub fn fmap S>(&self, f: F) -> SortedRecord { 49 | let mut v = Vec::with_capacity(self.rows.len()); 50 | for row in self.iter() { 51 | v.push(Row { 52 | label: row.label, 53 | span: row.span, 54 | data: f(&row.data), 55 | }); 56 | } 57 | SortedRecord { rows: v } 58 | } 59 | 60 | pub fn iter(&self) -> std::slice::Iter> { 61 | self.rows.iter() 62 | } 63 | 64 | pub fn contains(&self, lab: &Symbol) -> Option<&Row> { 65 | for row in self.iter() { 66 | if &row.label == lab { 67 | return Some(row); 68 | } 69 | } 70 | None 71 | } 72 | } 73 | 74 | impl std::iter::IntoIterator for SortedRecord { 75 | type Item = Row; 76 | type IntoIter = std::vec::IntoIter>; 77 | fn into_iter(self) -> Self::IntoIter { 78 | self.rows.into_iter() 79 | } 80 | } 81 | 82 | impl std::ops::Deref for SortedRecord { 83 | type Target = Vec>; 84 | fn deref(&self) -> &Self::Target { 85 | &self.rows 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /crates/database/src/types.rs: -------------------------------------------------------------------------------- 1 | use super::arena::Arena; 2 | use super::*; 3 | use std::cell::{Cell, RefCell}; 4 | use std::collections::{HashMap, HashSet, VecDeque}; 5 | use std::rc::Rc; 6 | 7 | pub struct TypeVar<'ar> { 8 | pub id: usize, 9 | rank: Cell, 10 | pub data: Cell>>, 11 | } 12 | 13 | pub struct Flex<'ar> { 14 | pub known: SortedRecord<&'ar Type<'ar>>, 15 | pub unknown: Rc>>>>, 16 | } 17 | 18 | pub enum Type<'ar> { 19 | Var(&'ar TypeVar<'ar>), 20 | Con(Tycon, Vec<&'ar Type<'ar>>), 21 | Record(SortedRecord<&'ar Type<'ar>>), 22 | Flex(Flex<'ar>), 23 | } 24 | 25 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq)] 26 | pub struct Tycon { 27 | pub name: Symbol, 28 | pub arity: usize, 29 | } 30 | 31 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash)] 32 | pub struct Constructor { 33 | pub name: Symbol, 34 | pub type_id: TypeId, 35 | pub tag: u8, 36 | pub arity: u8, 37 | pub type_arity: u8, 38 | } 39 | 40 | #[derive(Clone)] 41 | pub enum Scheme<'ar> { 42 | Mono(&'ar Type<'ar>), 43 | Poly(Vec, &'ar Type<'ar>), 44 | } 45 | 46 | impl<'ar> Type<'ar> { 47 | pub fn tyvar_id(&self) -> usize { 48 | match self { 49 | Type::Var(tv) => tv.id, 50 | _ => panic!("internal compiler bug"), 51 | } 52 | } 53 | 54 | /// 'de-arrow' an arrow type, returning the argument and result type 55 | pub fn de_arrow(&self) -> Option<(&'_ Type<'ar>, &'_ Type<'ar>)> { 56 | match self { 57 | Type::Con(builtin::tycons::T_ARROW, v) => Some((v[0], v[1])), 58 | Type::Var(tv) => { 59 | if let Some(ty) = tv.ty() { 60 | ty.de_arrow() 61 | } else { 62 | None 63 | } 64 | } 65 | _ => None, 66 | } 67 | } 68 | 69 | /// Pre-order BFS 70 | pub fn visit)>(&self, mut f: F) { 71 | let mut queue = VecDeque::new(); 72 | queue.push_back(self); 73 | 74 | while let Some(ty) = queue.pop_front() { 75 | f(ty); 76 | match ty { 77 | Type::Var(x) => { 78 | if let Some(link) = x.ty() { 79 | queue.push_back(link); 80 | } 81 | } 82 | Type::Con(_, tys) => { 83 | for ty in tys { 84 | queue.push_back(ty); 85 | } 86 | } 87 | Type::Record(rows) => { 88 | for row in rows.iter() { 89 | queue.push_back(&row.data); 90 | } 91 | } 92 | Type::Flex(flex) => { 93 | for row in flex.known.iter() { 94 | queue.push_back(&row.data); 95 | } 96 | if let Some(link) = &*flex.unknown.borrow() { 97 | // TODO: Should this even be possible? If a flex has it's 98 | // unknown set, then shouldn't it be promoted to a concrete 99 | // record type? 100 | for row in link.iter() { 101 | queue.push_back(&row.data); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | } 108 | 109 | /// Perform a breadth-first traversal of a type, collecting it's 110 | /// associated type variables that have a rank greater than `rank` 111 | pub fn ftv_rank(&self, rank: usize) -> Vec { 112 | let mut set = Vec::new(); 113 | let mut uniq = HashSet::new(); 114 | let mut queue = VecDeque::new(); 115 | queue.push_back(self); 116 | 117 | while let Some(ty) = queue.pop_front() { 118 | match ty { 119 | Type::Var(x) => match x.ty() { 120 | None => { 121 | if x.rank() > rank && uniq.insert(x.id) { 122 | set.push(x.id); 123 | } 124 | } 125 | Some(link) => { 126 | queue.push_back(link); 127 | } 128 | }, 129 | Type::Con(_, tys) => { 130 | for ty in tys { 131 | queue.push_back(ty); 132 | } 133 | } 134 | Type::Record(rows) => { 135 | for row in rows.iter() { 136 | queue.push_back(&row.data); 137 | } 138 | } 139 | Type::Flex(flex) => { 140 | for row in flex.known.iter() { 141 | queue.push_back(&row.data); 142 | } 143 | if let Some(link) = &*flex.unknown.borrow() { 144 | // TODO: Should this even be possible? If a flex has it's 145 | // unknown set, then shouldn't it be promoted to a concrete 146 | // record type? 147 | for row in link.iter() { 148 | queue.push_back(&row.data); 149 | } 150 | } 151 | } 152 | } 153 | } 154 | set 155 | } 156 | 157 | /// Apply a substitution to a type 158 | pub fn apply( 159 | &'ar self, 160 | arena: &'ar Arena<'ar>, 161 | map: &HashMap>, 162 | ) -> &'ar Type<'ar> { 163 | match self { 164 | Type::Var(x) => match x.ty() { 165 | Some(ty) => ty.apply(arena, map), 166 | None => { 167 | match map.get(&x.id) { 168 | Some(ty) => ty, 169 | None => self, 170 | } 171 | // map.get(&x.id).copied().unwrap_or(self), 172 | } 173 | }, 174 | Type::Con(tc, vars) => arena.alloc(Type::Con( 175 | *tc, 176 | vars.into_iter().map(|ty| ty.apply(arena, map)).collect(), 177 | )), 178 | Type::Record(rows) => arena.alloc(Type::Record(rows.fmap(|ty| ty.apply(arena, map)))), 179 | Type::Flex(flex) => { 180 | let flex_inner = Flex::new(flex.known.fmap(|ty| ty.apply(arena, map))); 181 | if let Some(linked) = &*flex.unknown.borrow() { 182 | // TODO: Should this even be possible? If a flex has it's 183 | // unknown set, then shouldn't it be promoted to a concrete 184 | // record type? 185 | let mut u = flex_inner.unknown.borrow_mut(); 186 | *u = Some(linked.fmap(|ty| ty.apply(arena, map))); 187 | } 188 | 189 | arena.alloc(Type::Flex(flex_inner)) 190 | } 191 | } 192 | } 193 | 194 | /// Check for potential cyclic occurences of `tyvar` in `self`. 195 | /// N.B. This function has potential side effects, in that it may promote 196 | /// the associated rank of `tyvar` to the rank of `self`, if `self` is also 197 | /// a type variable 198 | pub fn occurs_check(&self, tyvar: &TypeVar) -> bool { 199 | match &self { 200 | Type::Var(x) => { 201 | if let Some(info) = x.ty() { 202 | info.occurs_check(tyvar) 203 | } else { 204 | let curr = x.rank(); 205 | let min_rank = curr.min(tyvar.rank()); 206 | if min_rank < curr { 207 | // println!("promoting type var {} {}->{}", fresh_name(x.id), x.rank(), min_rank); 208 | x.rank.set(min_rank); 209 | } 210 | x.id == tyvar.id 211 | } 212 | } 213 | Type::Con(_, tys) => tys.iter().any(|ty| ty.occurs_check(tyvar)), 214 | Type::Record(rows) => rows.iter().any(|r| r.data.occurs_check(tyvar)), 215 | Type::Flex(flex) => { 216 | let known = flex.known.iter().any(|r| r.data.occurs_check(tyvar)); 217 | let unknown = match &*flex.unknown.borrow() { 218 | // TODO: Should this even be possible? If a flex has it's 219 | // unknown set, then shouldn't it be promoted to a concrete 220 | // record type? 221 | Some(link) => link.iter().any(|r| r.data.occurs_check(tyvar)), 222 | None => false, 223 | }; 224 | 225 | known || unknown 226 | } 227 | } 228 | } 229 | } 230 | 231 | impl Tycon { 232 | pub const fn new(name: Symbol, arity: usize) -> Tycon { 233 | Tycon { name, arity } 234 | } 235 | } 236 | 237 | impl<'ar> Scheme<'ar> { 238 | pub fn arity(&self) -> usize { 239 | match self { 240 | Scheme::Mono(_) => 0, 241 | Scheme::Poly(tyvars, _) => tyvars.len(), 242 | } 243 | } 244 | 245 | pub fn apply(&self, arena: &'ar Arena<'ar>, args: Vec<&'ar Type<'ar>>) -> &'ar Type<'ar> { 246 | match self { 247 | Scheme::Mono(ty) => ty, 248 | Scheme::Poly(vars, ty) => { 249 | if vars.len() > args.len() { 250 | unimplemented!() 251 | } else if vars.len() == args.len() { 252 | let map = vars 253 | .iter() 254 | .copied() 255 | .zip(args.into_iter()) 256 | .collect::>>(); 257 | ty.apply(arena, &map) 258 | } else { 259 | panic!("internal compiler error, not checking scheme arity") 260 | } 261 | } 262 | } 263 | } 264 | 265 | pub fn new(ty: &'ar Type<'ar>, tyvars: Vec) -> Scheme<'ar> { 266 | match tyvars.len() { 267 | 0 => Scheme::Mono(ty), 268 | _ => Scheme::Poly(tyvars, ty), 269 | } 270 | } 271 | } 272 | 273 | impl<'ar> TypeVar<'ar> { 274 | pub fn new(id: usize, rank: usize) -> TypeVar<'ar> { 275 | let data = Cell::new(None); 276 | TypeVar { 277 | id, 278 | rank: Cell::new(rank), 279 | data, 280 | } 281 | } 282 | 283 | pub fn ty(&self) -> Option<&'ar Type<'ar>> { 284 | self.data.get() 285 | } 286 | 287 | fn rank(&self) -> usize { 288 | self.rank.get() 289 | } 290 | } 291 | 292 | impl<'ar> Flex<'ar> { 293 | pub fn new(known: SortedRecord<&'ar Type<'ar>>) -> Flex<'ar> { 294 | let unknown = Rc::new(RefCell::new(None)); 295 | Flex { known, unknown } 296 | } 297 | 298 | pub fn to_rigid(&self) -> Option>> { 299 | let borrow = &*self.unknown.borrow(); 300 | let fields = borrow.as_ref()?; 301 | let merge = self 302 | .known 303 | .iter() 304 | .chain(fields.iter()) 305 | .copied() 306 | .collect::>>(); 307 | Some(SortedRecord::new(merge)) 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /crates/sml-analyzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sml-analyzer" 3 | version = "0.1.0" 4 | authors = ["Michael Lazear "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | lsp-server = "0.3.3" 11 | log = "0.4.3" 12 | lsp-types = "0.63.0" 13 | flexi_logger = "0.14.0" 14 | 15 | sml-util = { git = "https://github.com/SomewhatML/sml-compiler/" } 16 | sml-frontend = { git = "https://github.com/SomewhatML/sml-compiler/" } 17 | sml-core = { git = "https://github.com/SomewhatML/sml-compiler/" } 18 | 19 | database = { path = "../database" } 20 | 21 | serde_json = "1.0.34" 22 | serde = { version = "1.0.83", features = ["derive"] } 23 | crossbeam-channel = "0.4" 24 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/completions.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | fn keyword(s: &str) -> CompletionItem { 4 | let mut c = CompletionItem::new_simple(s.into(), "keyword".into()); 5 | c.kind = Some(CompletionItemKind::Keyword); 6 | c 7 | } 8 | 9 | mod snippets { 10 | use super::*; 11 | 12 | #[inline] 13 | fn template(kw: &str, snippet: &str) -> CompletionItem { 14 | CompletionItem { 15 | label: kw.into(), 16 | detail: Some(kw.into()), 17 | kind: Some(CompletionItemKind::Keyword), 18 | insert_text_format: Some(InsertTextFormat::Snippet), 19 | insert_text: Some(format!("{} {}", kw, snippet)), 20 | ..CompletionItem::default() 21 | } 22 | } 23 | 24 | pub fn decl_let() -> CompletionItem { 25 | template("let", "${1:declaration} in ${2:expr} end$0") 26 | } 27 | 28 | pub fn decl_local() -> CompletionItem { 29 | template("local", "${1:declaration} in ${2:expr} end$0") 30 | } 31 | 32 | pub fn expr_case() -> CompletionItem { 33 | template("case", "${1:expr} of\n| ${2:pat} => ${3:expr}\nend$0") 34 | } 35 | 36 | pub fn expr_fn() -> CompletionItem { 37 | CompletionItem { 38 | label: "fn".into(), 39 | detail: Some("fn".into()), 40 | kind: Some(CompletionItemKind::Keyword), 41 | insert_text_format: Some(InsertTextFormat::Snippet), 42 | insert_text: Some("(fn ${1:arg} => ${0:body})".into()), 43 | ..CompletionItem::default() 44 | } 45 | } 46 | 47 | pub fn expr_if() -> CompletionItem { 48 | template( 49 | "if", 50 | "${1:condition} then ${2:consquence} else ${0:alternate}", 51 | ) 52 | } 53 | } 54 | 55 | pub fn keyword_completions() -> Vec { 56 | vec![ 57 | keyword("and"), 58 | keyword("andalso"), 59 | keyword("as"), 60 | snippets::expr_case(), 61 | keyword("datatype"), 62 | keyword("do"), 63 | keyword("else"), 64 | keyword("end"), 65 | keyword("exception"), 66 | snippets::expr_fn(), 67 | keyword("fun"), 68 | keyword("functor"), 69 | keyword("handle"), 70 | snippets::expr_if(), 71 | keyword("in"), 72 | keyword("infix"), 73 | keyword("infixr"), 74 | snippets::decl_let(), 75 | snippets::decl_local(), 76 | keyword("nonfix"), 77 | keyword("of"), 78 | keyword("op"), 79 | keyword("open"), 80 | keyword("orelse"), 81 | keyword("primitive"), 82 | keyword("raise"), 83 | keyword("rec"), 84 | keyword("then"), 85 | keyword("type"), 86 | keyword("val"), 87 | keyword("with"), 88 | keyword("withtype"), 89 | keyword("while"), 90 | keyword("sig"), 91 | keyword("signature"), 92 | keyword("struct"), 93 | keyword("structure"), 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/dispatch.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn request<'a>(r: Request, conn: &'a Connection) -> RequestDispatch { 4 | RequestDispatch { 5 | data: Some(r), 6 | conn, 7 | } 8 | } 9 | 10 | pub fn notification(n: Notification) -> NotificationDispatch { 11 | NotificationDispatch { data: Some(n) } 12 | } 13 | 14 | pub struct NotificationDispatch { 15 | data: Option, 16 | } 17 | 18 | impl NotificationDispatch { 19 | pub fn handle(&mut self, f: F) -> &mut Self 20 | where 21 | R: lsp_types::notification::Notification, 22 | R::Params: serde::de::DeserializeOwned, 23 | F: FnOnce(R::Params), 24 | { 25 | let n = match self.data.take() { 26 | Some(n) => n, 27 | None => return self, 28 | }; 29 | 30 | let n = match cast_not::(n) { 31 | Ok(params) => { 32 | f(params); 33 | return self; 34 | } 35 | Err(not) => not, 36 | }; 37 | self.data = Some(n); 38 | self 39 | } 40 | } 41 | 42 | pub struct RequestDispatch<'a> { 43 | data: Option, 44 | conn: &'a Connection, 45 | } 46 | 47 | impl<'a> RequestDispatch<'a> { 48 | pub fn handle( 49 | &mut self, 50 | f: F, 51 | ) -> Result<&mut Self, crossbeam_channel::SendError> 52 | where 53 | R: lsp_types::request::Request, 54 | R::Params: serde::de::DeserializeOwned, 55 | T: serde::ser::Serialize, 56 | F: FnOnce(R::Params) -> T, 57 | { 58 | let n = match self.data.take() { 59 | Some(n) => n, 60 | None => return Ok(self), 61 | }; 62 | 63 | let n = match cast::(n) { 64 | Ok((id, params)) => { 65 | let result = f(params); 66 | let result = serde_json::to_value(&result).unwrap(); 67 | let resp = Response { 68 | id, 69 | result: Some(result), 70 | error: None, 71 | }; 72 | self.conn.sender.send(Message::Response(resp))?; 73 | return Ok(self); 74 | } 75 | Err(not) => not, 76 | }; 77 | self.data = Some(n); 78 | Ok(self) 79 | } 80 | } 81 | 82 | fn cast(req: Request) -> Result<(RequestId, R::Params), Request> 83 | where 84 | R: lsp_types::request::Request, 85 | R::Params: serde::de::DeserializeOwned, 86 | { 87 | req.extract(R::METHOD) 88 | } 89 | 90 | fn cast_not(req: Notification) -> Result 91 | where 92 | R: lsp_types::notification::Notification, 93 | R::Params: serde::de::DeserializeOwned, 94 | { 95 | req.extract(R::METHOD) 96 | } 97 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::error::Error; 3 | use std::time::Instant; 4 | 5 | use log::info; 6 | use lsp_types::{ 7 | notification::{DidChangeTextDocument, DidOpenTextDocument, DidSaveTextDocument}, 8 | request::{Completion, GotoDefinition, HoverRequest}, 9 | InitializeParams, ServerCapabilities, *, 10 | }; 11 | 12 | use lsp_server::{Connection, Message, Notification, Request, RequestId, Response}; 13 | use serde::Serialize; 14 | 15 | use sml_util::{interner::*, span::Span}; 16 | 17 | use database::Database; 18 | 19 | mod completions; 20 | mod dispatch; 21 | mod state; 22 | mod types; 23 | mod util; 24 | 25 | use state::GlobalState; 26 | 27 | fn main() -> Result<(), Box> { 28 | // Set up logging. Because `stdio_transport` gets a lock on stdout and stdin, we must have 29 | // our logging only write out to stderr. 30 | flexi_logger::Logger::with_str("info").start().unwrap(); 31 | info!("starting sml-analyzer"); 32 | 33 | // Create the transport. Includes the stdio (stdin and stdout) versions but this could 34 | // also be implemented to use sockets or HTTP. 35 | let (connection, io_threads) = Connection::stdio(); 36 | 37 | // Run the server and wait for the two threads to end (typically by trigger LSP Exit event). 38 | 39 | let caps = ServerCapabilities { 40 | text_document_sync: Some(TextDocumentSyncCapability::Kind( 41 | TextDocumentSyncKind::Incremental, 42 | )), 43 | hover_provider: Some(true), 44 | completion_provider: Some(CompletionOptions { 45 | resolve_provider: Some(false), 46 | trigger_characters: Some(vec![':'.to_string()]), 47 | work_done_progress_options: Default::default(), 48 | }), 49 | definition_provider: Some(true), 50 | ..ServerCapabilities::default() 51 | }; 52 | 53 | let server_capabilities = serde_json::to_value(&caps).unwrap(); 54 | let initialization_params = connection.initialize(server_capabilities)?; 55 | 56 | let owned_arena = database::arena::OwnedArena::new(); 57 | let borrow = owned_arena.borrow(); 58 | 59 | let mut state = GlobalState::new(&borrow, connection.sender.clone()); 60 | 61 | main_loop(&connection, initialization_params, &mut state)?; 62 | io_threads.join()?; 63 | 64 | // Shut down gracefully. 65 | info!("shutting down server"); 66 | Ok(()) 67 | } 68 | 69 | fn main_loop<'arena>( 70 | connection: &Connection, 71 | params: serde_json::Value, 72 | state: &mut GlobalState<'arena>, 73 | ) -> Result<(), Box> { 74 | let _params: InitializeParams = serde_json::from_value(params).unwrap(); 75 | info!("starting example main loop"); 76 | for msg in &connection.receiver { 77 | // info!("got msg: {:?}", msg); 78 | match msg { 79 | Message::Request(req) => { 80 | if connection.handle_shutdown(&req)? { 81 | return Ok(()); 82 | } 83 | 84 | dispatch::request(req, &connection) 85 | .handle::(|params| state.hover_request(params))? 86 | .handle::(|params| state.completion_req(params))? 87 | .handle::(|params| state.goto_def_request(params))?; 88 | } 89 | Message::Response(_) => { 90 | // info!("got response: {:?}", resp); 91 | } 92 | Message::Notification(not) => { 93 | dispatch::notification(not) 94 | .handle::(|params| state.open(params)) 95 | .handle::(|params| state.update(params)) 96 | .handle::(|params| { 97 | state.parse(¶ms.text_document.uri) 98 | }); 99 | } 100 | } 101 | } 102 | Ok(()) 103 | } 104 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/state.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use lsp_types::request::GotoDefinitionResponse; 3 | 4 | pub struct GlobalState<'arena> { 5 | text_cache: HashMap, 6 | kw_completions: Vec, 7 | interner: Interner, 8 | sender: crossbeam_channel::Sender, 9 | arena: &'arena database::arena::Arena<'arena>, 10 | db: Database<'arena>, 11 | } 12 | 13 | pub fn diag_convert(diag: sml_util::diagnostics::Diagnostic) -> Diagnostic { 14 | let sp = diag.primary.span; 15 | let message = diag.primary.info; 16 | let range = Range::new( 17 | Position::new(sp.start.line as u64, sp.start.col as u64), 18 | Position::new(sp.end.line as u64, sp.end.col as u64), 19 | ); 20 | let mut out = Diagnostic::new_simple(range, message); 21 | out.severity = Some(match diag.level { 22 | sml_util::diagnostics::Level::Bug => DiagnosticSeverity::Information, 23 | sml_util::diagnostics::Level::Warn => DiagnosticSeverity::Warning, 24 | sml_util::diagnostics::Level::Error => DiagnosticSeverity::Error, 25 | }); 26 | out 27 | } 28 | 29 | fn measure T>(f: F) -> (T, u128) { 30 | let start = Instant::now(); 31 | let r = f(); 32 | let stop = Instant::now().duration_since(start).as_micros(); 33 | (r, stop) 34 | } 35 | 36 | #[inline] 37 | fn in_span(pos: &Position, span: &Span) -> bool { 38 | if pos.line >= span.start.line as u64 && pos.line <= span.end.line as u64 { 39 | pos.character >= span.start.col as u64 && pos.character <= span.end.col as u64 40 | } else { 41 | false 42 | } 43 | } 44 | 45 | impl<'a> GlobalState<'a> { 46 | pub fn new( 47 | arena: &'a database::arena::Arena<'a>, 48 | sender: crossbeam_channel::Sender, 49 | ) -> GlobalState<'a> { 50 | GlobalState { 51 | text_cache: HashMap::default(), 52 | kw_completions: completions::keyword_completions(), 53 | interner: Interner::with_capacity(4096), 54 | sender, 55 | arena, 56 | db: Database::new(arena), 57 | } 58 | } 59 | 60 | pub fn parse(&mut self, url: &Url) { 61 | let data = match self.text_cache.get(url) { 62 | Some(data) => data, 63 | None => return, 64 | }; 65 | 66 | let mut parser = sml_frontend::parser::Parser::new(data, &mut self.interner); 67 | let ((res, diags), dur) = measure(|| (parser.parse_decl(), parser.diags)); 68 | // info!("parsing took {} us", dur); 69 | 70 | let mut st_diag = Vec::new(); 71 | match res { 72 | Ok(d) => { 73 | if !diags.is_empty() { 74 | for diag in diags { 75 | st_diag.push(diag_convert(diag)); 76 | } 77 | } 78 | self.db = Database::new(self.arena); 79 | let (_, dur) = measure(|| self.db.walk_decl(&d)); 80 | // info!("new elab took {} us", dur); 81 | 82 | let unify_errs = std::mem::replace(&mut self.db.unification_errors, Vec::new()); 83 | st_diag.extend( 84 | unify_errs 85 | .into_iter() 86 | .filter_map(|c| types::unify_error(c, &self.interner)), 87 | ); 88 | 89 | let diags = std::mem::replace(&mut self.db.diags, Vec::new()); 90 | if !diags.is_empty() { 91 | for diag in diags { 92 | st_diag.push(diag_convert(diag)); 93 | } 94 | } 95 | } 96 | Err(e) => { 97 | st_diag.push(diag_convert(e.to_diagnostic())); 98 | if !diags.is_empty() { 99 | for diag in diags { 100 | st_diag.push(diag_convert(diag)); 101 | } 102 | } 103 | } 104 | }; 105 | 106 | // info!("reporting {} errors for {:?}", st_diag.len(), url); 107 | 108 | self.send_notification::( 109 | lsp_types::PublishDiagnosticsParams { 110 | uri: url.clone(), 111 | diagnostics: st_diag, 112 | version: None, 113 | }, 114 | ); 115 | } 116 | 117 | pub(crate) fn send_notification( 118 | &mut self, 119 | params: N::Params, 120 | ) where 121 | N::Params: Serialize, 122 | { 123 | let not = lsp_server::Notification::new(N::METHOD.to_string(), params); 124 | self.send(not.into()); 125 | } 126 | 127 | fn send(&self, message: lsp_server::Message) { 128 | self.sender.send(message).unwrap() 129 | } 130 | } 131 | 132 | impl<'a> GlobalState<'a> { 133 | fn map_values(&self, sym: Symbol, ty: &database::Type<'_>) -> Option { 134 | let name = self.interner.get(sym)?; 135 | let mut alpha = types::Alpha::default(); 136 | let mut out = String::new(); 137 | alpha.write_type2(ty, &self.interner, &mut out).ok()?; 138 | 139 | let mut c = CompletionItem::new_simple(name.into(), format!("{}: {}", name, out)); 140 | c.kind = Some(CompletionItemKind::Value); 141 | Some(c) 142 | } 143 | 144 | fn map_types(&self, sym: Symbol, ty: Option<&database::Type<'_>>) -> Option { 145 | let name = self.interner.get(sym)?; 146 | let mut c = if let Some(ty) = ty { 147 | let mut alpha = types::Alpha::default(); 148 | let mut out = String::new(); 149 | alpha.write_type2(ty, &self.interner, &mut out).ok()?; 150 | CompletionItem::new_simple(name.into(), format!("{}: {}", name, out)) 151 | } else { 152 | CompletionItem::new_simple(name.into(), format!("{}", name)) 153 | }; 154 | c.kind = Some(CompletionItemKind::TypeParameter); 155 | c.insert_text = Some(format!(" {}", &c.label)); 156 | Some(c) 157 | } 158 | 159 | pub fn open(&mut self, params: DidOpenTextDocumentParams) { 160 | self.text_cache 161 | .insert(params.text_document.uri.clone(), params.text_document.text); 162 | self.parse(¶ms.text_document.uri); 163 | } 164 | 165 | pub fn update(&mut self, params: DidChangeTextDocumentParams) { 166 | match self.text_cache.get_mut(¶ms.text_document.uri) { 167 | Some(data) => util::apply_changes(data, params.content_changes), 168 | None => {} 169 | } 170 | } 171 | 172 | fn position_to_type(&self, pos: Position) -> Option<&'a database::Type<'a>> { 173 | self.db 174 | .bindings 175 | .iter() 176 | .find(|(sp, _)| in_span(&pos, sp)) 177 | .map(|(_, ty)| *ty) 178 | } 179 | 180 | pub fn hover_request(&mut self, params: TextDocumentPositionParams) -> Option { 181 | self.position_to_type(params.position).map(|ty| { 182 | let mut alpha = types::Alpha::default(); 183 | let mut out = String::with_capacity(64); 184 | 185 | alpha.write_type2(ty, &self.interner, &mut out).unwrap(); 186 | 187 | Hover { 188 | contents: HoverContents::Scalar(MarkedString::from_markdown(format!( 189 | "type: {}", 190 | out 191 | ))), 192 | range: None, 193 | } 194 | }) 195 | } 196 | 197 | pub fn completion_req(&mut self, params: CompletionParams) -> Option { 198 | let pos = params.text_document_position.position; 199 | let loc = sml_util::span::Location::new(pos.line as u16, pos.character as u16, 0); 200 | params.context.map( 201 | |ctx| match ctx.trigger_character.map(|s| s.chars().next()).flatten() { 202 | Some(':') => { 203 | let tycons = self 204 | .db 205 | .in_scope_types(loc) 206 | .into_iter() 207 | .filter_map(|(sym, ty)| self.map_types(sym, ty)) 208 | .collect::>(); 209 | CompletionResponse::Array(tycons) 210 | } 211 | _ => { 212 | let tycons = self 213 | .db 214 | .in_scope_values(loc) 215 | .into_iter() 216 | .filter_map(|(sym, ty)| self.map_values(sym, ty)) 217 | .chain(self.kw_completions.clone()) 218 | .collect::>(); 219 | 220 | CompletionResponse::Array(tycons) 221 | } 222 | }, 223 | ) 224 | } 225 | 226 | pub fn goto_def_request( 227 | &mut self, 228 | params: TextDocumentPositionParams, 229 | ) -> Option { 230 | use sml_util::span::Spanned; 231 | 232 | let pos = params.position; 233 | let loc = sml_util::span::Location::new(pos.line as u16, pos.character as u16, 0); 234 | 235 | let (_, name) = self 236 | .db 237 | .references 238 | .iter() 239 | .find(|(sp, _)| in_span(&pos, sp))?; 240 | let vals = self.db.in_scope_value_names(loc); 241 | let Spanned { span, .. } = vals.into_iter().find(|Spanned { data, .. }| data == name)?; 242 | 243 | let loc = Location::new(params.text_document.uri, crate::util::span_to_range(span)); 244 | Some(GotoDefinitionResponse::Scalar(loc)) 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/types.rs: -------------------------------------------------------------------------------- 1 | use sml_util::interner::*; 2 | use std::collections::HashMap; 3 | 4 | use database::CantUnify; 5 | 6 | fn span_to_range(sp: sml_util::span::Span) -> lsp_types::Range { 7 | lsp_types::Range::new( 8 | lsp_types::Position::new(sp.start.line as u64, sp.start.col as u64), 9 | lsp_types::Position::new(sp.end.line as u64, sp.end.col as u64), 10 | ) 11 | } 12 | 13 | pub fn unify_error<'a>(c: CantUnify<'a>, intern: &Interner) -> Option { 14 | let mut alpha = Alpha::default(); 15 | let mut ty1 = String::new(); 16 | let mut ty2 = String::new(); 17 | 18 | alpha.write_type2(c.ty1, intern, &mut ty1).ok()?; 19 | alpha.write_type2(c.ty2, intern, &mut ty2).ok()?; 20 | 21 | let sp = c.originating?; 22 | let diag = lsp_types::Diagnostic::new_simple( 23 | span_to_range(sp), 24 | format!( 25 | "Type error: {}: {} and {}\n{}", 26 | c.reason, ty1, ty2, c.message 27 | ), 28 | ); 29 | 30 | Some(diag) 31 | } 32 | 33 | // Alpha rename typevars to better letters 34 | #[derive(Default)] 35 | pub struct Alpha { 36 | map: HashMap, 37 | } 38 | 39 | fn fresh_name(x: usize) -> String { 40 | let last = ((x % 26) as u8 + 'a' as u8) as char; 41 | (0..x / 26) 42 | .map(|_| 'z') 43 | .chain(std::iter::once(last)) 44 | .collect::() 45 | } 46 | 47 | impl Alpha { 48 | fn gen(&mut self, id: usize) -> &str { 49 | let len = self.map.len(); 50 | self.map.entry(id).or_insert_with(|| fresh_name(len)) 51 | } 52 | 53 | fn write_record( 54 | &mut self, 55 | fields: &database::SortedRecord<&'_ database::Type<'_>>, 56 | flex: bool, 57 | interner: &Interner, 58 | f: &mut dyn std::fmt::Write, 59 | ) -> std::fmt::Result { 60 | let tuple = match fields.get(0) { 61 | Some(database::Row { 62 | label: Symbol::Tuple(_), 63 | .. 64 | }) => true, 65 | _ => false, 66 | }; 67 | 68 | if tuple { 69 | write!(f, "(")?; 70 | } else { 71 | write!(f, "{{")?; 72 | } 73 | for (idx, field) in fields.iter().enumerate() { 74 | if !tuple { 75 | write!(f, "{}:", interner.get(field.label).unwrap_or_else(|| "?"))?; 76 | } 77 | self.write_type2(field.data, interner, f)?; 78 | if idx != fields.len() - 1 { 79 | write!(f, ", ")?; 80 | } 81 | } 82 | if tuple { 83 | write!(f, ")") 84 | } else { 85 | if flex { 86 | write!(f, "...")?; 87 | } 88 | write!(f, "}}") 89 | } 90 | } 91 | 92 | pub fn write_type2( 93 | &mut self, 94 | ty: &database::Type<'_>, 95 | interner: &Interner, 96 | f: &mut dyn std::fmt::Write, 97 | ) -> std::fmt::Result { 98 | match ty { 99 | database::Type::Var(tvar) => match tvar.ty() { 100 | Some(bound) => self.write_type2(bound, interner, f), 101 | None => write!(f, "'{}", self.gen(tvar.id)), 102 | }, 103 | database::Type::Con(tc, args) => match tc { 104 | &database::builtin::tycons::T_ARROW => { 105 | self.write_type2(&args[0], interner, f)?; 106 | write!(f, " -> ")?; 107 | self.write_type2(&args[1], interner, f) 108 | } 109 | _ => { 110 | if args.is_empty() { 111 | write!(f, "{}", interner.get(tc.name).unwrap_or_else(|| "?")) 112 | } else { 113 | for arg in args { 114 | self.write_type2(*arg, interner, f)?; 115 | write!(f, " ")?; 116 | } 117 | write!(f, "{}", interner.get(tc.name).unwrap_or_else(|| "?")) 118 | } 119 | } 120 | }, 121 | database::Type::Record(fields) => self.write_record(fields, false, interner, f), 122 | database::Type::Flex(flex) => match flex.to_rigid() { 123 | Some(fields) => self.write_record(&fields, false, interner, f), 124 | None => self.write_record(&flex.known, true, interner, f), 125 | }, 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /crates/sml-analyzer/src/util.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn loc_to_position(loc: sml_util::span::Location) -> lsp_types::Position { 4 | Position::new(loc.line as u64, loc.col as u64) 5 | } 6 | 7 | pub fn position_to_loc(pos: lsp_types::Position) -> sml_util::span::Location { 8 | sml_util::span::Location::new(pos.line as u16, pos.character as u16, 0) 9 | } 10 | 11 | pub fn span_to_range(span: Span) -> Range { 12 | let start = loc_to_position(span.start); 13 | let end = loc_to_position(span.end); 14 | Range::new(start, end) 15 | } 16 | 17 | struct LineIndex<'s> { 18 | source: &'s str, 19 | lines: Vec, 20 | } 21 | 22 | impl<'s> LineIndex<'s> { 23 | fn new(source: &'s str) -> LineIndex { 24 | let mut lines = vec![0]; 25 | let mut abs = 0; 26 | for ch in source.chars() { 27 | abs += 1; 28 | if ch == '\n' { 29 | lines.push(abs); 30 | } 31 | } 32 | LineIndex { source, lines } 33 | } 34 | } 35 | 36 | // TODO: Absolutely broken 37 | pub fn apply_changes(prev: &mut String, changes: Vec) { 38 | for change in changes { 39 | let idx = LineIndex::new(prev); 40 | 41 | if let Some(range) = change.range { 42 | let a = idx.lines[range.start.line as usize] + range.start.character; 43 | let b = idx.lines[range.end.line as usize] + range.end.character; 44 | prev.replace_range(a as usize..b as usize, &change.text); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SomewhatML/sml-analyzer/fd5aa738a3d6c73e321a5352de256584c1144f4f/demo.gif -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SomewhatML/sml-analyzer/fd5aa738a3d6c73e321a5352de256584c1144f4f/demo.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sml-analyzer-client", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.10.4", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", 10 | "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.10.4", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", 19 | "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.10.4", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", 25 | "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.10.4", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | } 32 | }, 33 | "@types/color-name": { 34 | "version": "1.1.1", 35 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", 36 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", 37 | "dev": true 38 | }, 39 | "@types/eslint-visitor-keys": { 40 | "version": "1.0.0", 41 | "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 42 | "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", 43 | "dev": true 44 | }, 45 | "@types/json-schema": { 46 | "version": "7.0.5", 47 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", 48 | "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", 49 | "dev": true 50 | }, 51 | "@types/mocha": { 52 | "version": "7.0.2", 53 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", 54 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", 55 | "dev": true 56 | }, 57 | "@types/node": { 58 | "version": "12.12.51", 59 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.51.tgz", 60 | "integrity": "sha512-6ILqt8iNThALrxDv2Q4LyYFQxULQz96HKNIFd4s9QRQaiHINYeUpLqeU/2IU7YMtvipG1fQVAy//vY8/fX1Y9w==", 61 | "dev": true 62 | }, 63 | "@types/vscode": { 64 | "version": "1.43.0", 65 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.43.0.tgz", 66 | "integrity": "sha512-kIaR9qzd80rJOxePKpCB/mdy00mz8Apt2QA5Y6rdrKFn13QNFNeP3Hzmsf37Bwh/3cS7QjtAeGSK7wSqAU0sYQ==", 67 | "dev": true 68 | }, 69 | "@typescript-eslint/experimental-utils": { 70 | "version": "2.34.0", 71 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", 72 | "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", 73 | "dev": true, 74 | "requires": { 75 | "@types/json-schema": "^7.0.3", 76 | "@typescript-eslint/typescript-estree": "2.34.0", 77 | "eslint-scope": "^5.0.0", 78 | "eslint-utils": "^2.0.0" 79 | } 80 | }, 81 | "@typescript-eslint/parser": { 82 | "version": "2.34.0", 83 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", 84 | "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", 85 | "dev": true, 86 | "requires": { 87 | "@types/eslint-visitor-keys": "^1.0.0", 88 | "@typescript-eslint/experimental-utils": "2.34.0", 89 | "@typescript-eslint/typescript-estree": "2.34.0", 90 | "eslint-visitor-keys": "^1.1.0" 91 | } 92 | }, 93 | "@typescript-eslint/typescript-estree": { 94 | "version": "2.34.0", 95 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", 96 | "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", 97 | "dev": true, 98 | "requires": { 99 | "debug": "^4.1.1", 100 | "eslint-visitor-keys": "^1.1.0", 101 | "glob": "^7.1.6", 102 | "is-glob": "^4.0.1", 103 | "lodash": "^4.17.15", 104 | "semver": "^7.3.2", 105 | "tsutils": "^3.17.1" 106 | }, 107 | "dependencies": { 108 | "debug": { 109 | "version": "4.1.1", 110 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 111 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 112 | "dev": true, 113 | "requires": { 114 | "ms": "^2.1.1" 115 | } 116 | }, 117 | "ms": { 118 | "version": "2.1.2", 119 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 120 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 121 | "dev": true 122 | } 123 | } 124 | }, 125 | "acorn": { 126 | "version": "7.3.1", 127 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", 128 | "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", 129 | "dev": true 130 | }, 131 | "acorn-jsx": { 132 | "version": "5.2.0", 133 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", 134 | "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", 135 | "dev": true 136 | }, 137 | "agent-base": { 138 | "version": "4.3.0", 139 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", 140 | "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", 141 | "dev": true, 142 | "requires": { 143 | "es6-promisify": "^5.0.0" 144 | } 145 | }, 146 | "ajv": { 147 | "version": "6.12.3", 148 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", 149 | "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", 150 | "dev": true, 151 | "requires": { 152 | "fast-deep-equal": "^3.1.1", 153 | "fast-json-stable-stringify": "^2.0.0", 154 | "json-schema-traverse": "^0.4.1", 155 | "uri-js": "^4.2.2" 156 | } 157 | }, 158 | "ansi-colors": { 159 | "version": "4.1.1", 160 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 161 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 162 | "dev": true 163 | }, 164 | "ansi-escapes": { 165 | "version": "4.3.1", 166 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", 167 | "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", 168 | "dev": true, 169 | "requires": { 170 | "type-fest": "^0.11.0" 171 | }, 172 | "dependencies": { 173 | "type-fest": { 174 | "version": "0.11.0", 175 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", 176 | "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", 177 | "dev": true 178 | } 179 | } 180 | }, 181 | "ansi-regex": { 182 | "version": "5.0.0", 183 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 184 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 185 | "dev": true 186 | }, 187 | "ansi-styles": { 188 | "version": "3.2.1", 189 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 190 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 191 | "dev": true, 192 | "requires": { 193 | "color-convert": "^1.9.0" 194 | } 195 | }, 196 | "anymatch": { 197 | "version": "3.1.1", 198 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 199 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 200 | "dev": true, 201 | "requires": { 202 | "normalize-path": "^3.0.0", 203 | "picomatch": "^2.0.4" 204 | } 205 | }, 206 | "argparse": { 207 | "version": "1.0.10", 208 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 209 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 210 | "dev": true, 211 | "requires": { 212 | "sprintf-js": "~1.0.2" 213 | } 214 | }, 215 | "array.prototype.map": { 216 | "version": "1.0.2", 217 | "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", 218 | "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", 219 | "dev": true, 220 | "requires": { 221 | "define-properties": "^1.1.3", 222 | "es-abstract": "^1.17.0-next.1", 223 | "es-array-method-boxes-properly": "^1.0.0", 224 | "is-string": "^1.0.4" 225 | } 226 | }, 227 | "astral-regex": { 228 | "version": "1.0.0", 229 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 230 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 231 | "dev": true 232 | }, 233 | "balanced-match": { 234 | "version": "1.0.0", 235 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 236 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 237 | "dev": true 238 | }, 239 | "binary-extensions": { 240 | "version": "2.1.0", 241 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", 242 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", 243 | "dev": true 244 | }, 245 | "brace-expansion": { 246 | "version": "1.1.11", 247 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 248 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 249 | "dev": true, 250 | "requires": { 251 | "balanced-match": "^1.0.0", 252 | "concat-map": "0.0.1" 253 | } 254 | }, 255 | "braces": { 256 | "version": "3.0.2", 257 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 258 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 259 | "dev": true, 260 | "requires": { 261 | "fill-range": "^7.0.1" 262 | } 263 | }, 264 | "browser-stdout": { 265 | "version": "1.3.1", 266 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 267 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 268 | "dev": true 269 | }, 270 | "callsites": { 271 | "version": "3.1.0", 272 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 273 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 274 | "dev": true 275 | }, 276 | "camelcase": { 277 | "version": "5.3.1", 278 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 279 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 280 | "dev": true 281 | }, 282 | "chalk": { 283 | "version": "2.4.2", 284 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 285 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 286 | "dev": true, 287 | "requires": { 288 | "ansi-styles": "^3.2.1", 289 | "escape-string-regexp": "^1.0.5", 290 | "supports-color": "^5.3.0" 291 | } 292 | }, 293 | "chardet": { 294 | "version": "0.7.0", 295 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 296 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 297 | "dev": true 298 | }, 299 | "chokidar": { 300 | "version": "3.3.1", 301 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", 302 | "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", 303 | "dev": true, 304 | "requires": { 305 | "anymatch": "~3.1.1", 306 | "braces": "~3.0.2", 307 | "fsevents": "~2.1.2", 308 | "glob-parent": "~5.1.0", 309 | "is-binary-path": "~2.1.0", 310 | "is-glob": "~4.0.1", 311 | "normalize-path": "~3.0.0", 312 | "readdirp": "~3.3.0" 313 | } 314 | }, 315 | "cli-cursor": { 316 | "version": "3.1.0", 317 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", 318 | "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", 319 | "dev": true, 320 | "requires": { 321 | "restore-cursor": "^3.1.0" 322 | } 323 | }, 324 | "cli-width": { 325 | "version": "3.0.0", 326 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", 327 | "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", 328 | "dev": true 329 | }, 330 | "cliui": { 331 | "version": "5.0.0", 332 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 333 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", 334 | "dev": true, 335 | "requires": { 336 | "string-width": "^3.1.0", 337 | "strip-ansi": "^5.2.0", 338 | "wrap-ansi": "^5.1.0" 339 | }, 340 | "dependencies": { 341 | "emoji-regex": { 342 | "version": "7.0.3", 343 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 344 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 345 | "dev": true 346 | }, 347 | "is-fullwidth-code-point": { 348 | "version": "2.0.0", 349 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 350 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 351 | "dev": true 352 | }, 353 | "string-width": { 354 | "version": "3.1.0", 355 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 356 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 357 | "dev": true, 358 | "requires": { 359 | "emoji-regex": "^7.0.1", 360 | "is-fullwidth-code-point": "^2.0.0", 361 | "strip-ansi": "^5.1.0" 362 | } 363 | } 364 | } 365 | }, 366 | "color-convert": { 367 | "version": "1.9.3", 368 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 369 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 370 | "dev": true, 371 | "requires": { 372 | "color-name": "1.1.3" 373 | } 374 | }, 375 | "color-name": { 376 | "version": "1.1.3", 377 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 378 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 379 | "dev": true 380 | }, 381 | "concat-map": { 382 | "version": "0.0.1", 383 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 384 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 385 | "dev": true 386 | }, 387 | "cross-spawn": { 388 | "version": "6.0.5", 389 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 390 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 391 | "dev": true, 392 | "requires": { 393 | "nice-try": "^1.0.4", 394 | "path-key": "^2.0.1", 395 | "semver": "^5.5.0", 396 | "shebang-command": "^1.2.0", 397 | "which": "^1.2.9" 398 | }, 399 | "dependencies": { 400 | "semver": { 401 | "version": "5.7.1", 402 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 403 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 404 | "dev": true 405 | } 406 | } 407 | }, 408 | "debug": { 409 | "version": "3.1.0", 410 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 411 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 412 | "dev": true, 413 | "requires": { 414 | "ms": "2.0.0" 415 | } 416 | }, 417 | "decamelize": { 418 | "version": "1.2.0", 419 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 420 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 421 | "dev": true 422 | }, 423 | "deep-is": { 424 | "version": "0.1.3", 425 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 426 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 427 | "dev": true 428 | }, 429 | "define-properties": { 430 | "version": "1.1.3", 431 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 432 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 433 | "dev": true, 434 | "requires": { 435 | "object-keys": "^1.0.12" 436 | } 437 | }, 438 | "diff": { 439 | "version": "4.0.2", 440 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 441 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 442 | "dev": true 443 | }, 444 | "doctrine": { 445 | "version": "3.0.0", 446 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 447 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 448 | "dev": true, 449 | "requires": { 450 | "esutils": "^2.0.2" 451 | } 452 | }, 453 | "emoji-regex": { 454 | "version": "8.0.0", 455 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 456 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 457 | "dev": true 458 | }, 459 | "es-abstract": { 460 | "version": "1.17.6", 461 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", 462 | "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", 463 | "dev": true, 464 | "requires": { 465 | "es-to-primitive": "^1.2.1", 466 | "function-bind": "^1.1.1", 467 | "has": "^1.0.3", 468 | "has-symbols": "^1.0.1", 469 | "is-callable": "^1.2.0", 470 | "is-regex": "^1.1.0", 471 | "object-inspect": "^1.7.0", 472 | "object-keys": "^1.1.1", 473 | "object.assign": "^4.1.0", 474 | "string.prototype.trimend": "^1.0.1", 475 | "string.prototype.trimstart": "^1.0.1" 476 | } 477 | }, 478 | "es-array-method-boxes-properly": { 479 | "version": "1.0.0", 480 | "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", 481 | "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", 482 | "dev": true 483 | }, 484 | "es-get-iterator": { 485 | "version": "1.1.0", 486 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", 487 | "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", 488 | "dev": true, 489 | "requires": { 490 | "es-abstract": "^1.17.4", 491 | "has-symbols": "^1.0.1", 492 | "is-arguments": "^1.0.4", 493 | "is-map": "^2.0.1", 494 | "is-set": "^2.0.1", 495 | "is-string": "^1.0.5", 496 | "isarray": "^2.0.5" 497 | } 498 | }, 499 | "es-to-primitive": { 500 | "version": "1.2.1", 501 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 502 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 503 | "dev": true, 504 | "requires": { 505 | "is-callable": "^1.1.4", 506 | "is-date-object": "^1.0.1", 507 | "is-symbol": "^1.0.2" 508 | } 509 | }, 510 | "es6-promise": { 511 | "version": "4.2.8", 512 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 513 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", 514 | "dev": true 515 | }, 516 | "es6-promisify": { 517 | "version": "5.0.0", 518 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 519 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 520 | "dev": true, 521 | "requires": { 522 | "es6-promise": "^4.0.3" 523 | } 524 | }, 525 | "escape-string-regexp": { 526 | "version": "1.0.5", 527 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 528 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 529 | "dev": true 530 | }, 531 | "eslint": { 532 | "version": "6.8.0", 533 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", 534 | "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", 535 | "dev": true, 536 | "requires": { 537 | "@babel/code-frame": "^7.0.0", 538 | "ajv": "^6.10.0", 539 | "chalk": "^2.1.0", 540 | "cross-spawn": "^6.0.5", 541 | "debug": "^4.0.1", 542 | "doctrine": "^3.0.0", 543 | "eslint-scope": "^5.0.0", 544 | "eslint-utils": "^1.4.3", 545 | "eslint-visitor-keys": "^1.1.0", 546 | "espree": "^6.1.2", 547 | "esquery": "^1.0.1", 548 | "esutils": "^2.0.2", 549 | "file-entry-cache": "^5.0.1", 550 | "functional-red-black-tree": "^1.0.1", 551 | "glob-parent": "^5.0.0", 552 | "globals": "^12.1.0", 553 | "ignore": "^4.0.6", 554 | "import-fresh": "^3.0.0", 555 | "imurmurhash": "^0.1.4", 556 | "inquirer": "^7.0.0", 557 | "is-glob": "^4.0.0", 558 | "js-yaml": "^3.13.1", 559 | "json-stable-stringify-without-jsonify": "^1.0.1", 560 | "levn": "^0.3.0", 561 | "lodash": "^4.17.14", 562 | "minimatch": "^3.0.4", 563 | "mkdirp": "^0.5.1", 564 | "natural-compare": "^1.4.0", 565 | "optionator": "^0.8.3", 566 | "progress": "^2.0.0", 567 | "regexpp": "^2.0.1", 568 | "semver": "^6.1.2", 569 | "strip-ansi": "^5.2.0", 570 | "strip-json-comments": "^3.0.1", 571 | "table": "^5.2.3", 572 | "text-table": "^0.2.0", 573 | "v8-compile-cache": "^2.0.3" 574 | }, 575 | "dependencies": { 576 | "debug": { 577 | "version": "4.1.1", 578 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 579 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 580 | "dev": true, 581 | "requires": { 582 | "ms": "^2.1.1" 583 | } 584 | }, 585 | "eslint-utils": { 586 | "version": "1.4.3", 587 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", 588 | "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", 589 | "dev": true, 590 | "requires": { 591 | "eslint-visitor-keys": "^1.1.0" 592 | } 593 | }, 594 | "ms": { 595 | "version": "2.1.2", 596 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 597 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 598 | "dev": true 599 | }, 600 | "semver": { 601 | "version": "6.3.0", 602 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 603 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 604 | "dev": true 605 | } 606 | } 607 | }, 608 | "eslint-scope": { 609 | "version": "5.1.0", 610 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", 611 | "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", 612 | "dev": true, 613 | "requires": { 614 | "esrecurse": "^4.1.0", 615 | "estraverse": "^4.1.1" 616 | } 617 | }, 618 | "eslint-utils": { 619 | "version": "2.1.0", 620 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", 621 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", 622 | "dev": true, 623 | "requires": { 624 | "eslint-visitor-keys": "^1.1.0" 625 | } 626 | }, 627 | "eslint-visitor-keys": { 628 | "version": "1.3.0", 629 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 630 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 631 | "dev": true 632 | }, 633 | "espree": { 634 | "version": "6.2.1", 635 | "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", 636 | "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", 637 | "dev": true, 638 | "requires": { 639 | "acorn": "^7.1.1", 640 | "acorn-jsx": "^5.2.0", 641 | "eslint-visitor-keys": "^1.1.0" 642 | } 643 | }, 644 | "esprima": { 645 | "version": "4.0.1", 646 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 647 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 648 | "dev": true 649 | }, 650 | "esquery": { 651 | "version": "1.3.1", 652 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", 653 | "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", 654 | "dev": true, 655 | "requires": { 656 | "estraverse": "^5.1.0" 657 | }, 658 | "dependencies": { 659 | "estraverse": { 660 | "version": "5.1.0", 661 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", 662 | "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", 663 | "dev": true 664 | } 665 | } 666 | }, 667 | "esrecurse": { 668 | "version": "4.2.1", 669 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 670 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 671 | "dev": true, 672 | "requires": { 673 | "estraverse": "^4.1.0" 674 | } 675 | }, 676 | "estraverse": { 677 | "version": "4.3.0", 678 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 679 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 680 | "dev": true 681 | }, 682 | "esutils": { 683 | "version": "2.0.3", 684 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 685 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 686 | "dev": true 687 | }, 688 | "external-editor": { 689 | "version": "3.1.0", 690 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 691 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 692 | "dev": true, 693 | "requires": { 694 | "chardet": "^0.7.0", 695 | "iconv-lite": "^0.4.24", 696 | "tmp": "^0.0.33" 697 | } 698 | }, 699 | "fast-deep-equal": { 700 | "version": "3.1.3", 701 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 702 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 703 | "dev": true 704 | }, 705 | "fast-json-stable-stringify": { 706 | "version": "2.1.0", 707 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 708 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 709 | "dev": true 710 | }, 711 | "fast-levenshtein": { 712 | "version": "2.0.6", 713 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 714 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 715 | "dev": true 716 | }, 717 | "figures": { 718 | "version": "3.2.0", 719 | "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", 720 | "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", 721 | "dev": true, 722 | "requires": { 723 | "escape-string-regexp": "^1.0.5" 724 | } 725 | }, 726 | "file-entry-cache": { 727 | "version": "5.0.1", 728 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 729 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 730 | "dev": true, 731 | "requires": { 732 | "flat-cache": "^2.0.1" 733 | } 734 | }, 735 | "fill-range": { 736 | "version": "7.0.1", 737 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 738 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 739 | "dev": true, 740 | "requires": { 741 | "to-regex-range": "^5.0.1" 742 | } 743 | }, 744 | "find-up": { 745 | "version": "4.1.0", 746 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 747 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 748 | "dev": true, 749 | "requires": { 750 | "locate-path": "^5.0.0", 751 | "path-exists": "^4.0.0" 752 | } 753 | }, 754 | "flat": { 755 | "version": "4.1.0", 756 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", 757 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", 758 | "dev": true, 759 | "requires": { 760 | "is-buffer": "~2.0.3" 761 | } 762 | }, 763 | "flat-cache": { 764 | "version": "2.0.1", 765 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 766 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 767 | "dev": true, 768 | "requires": { 769 | "flatted": "^2.0.0", 770 | "rimraf": "2.6.3", 771 | "write": "1.0.3" 772 | }, 773 | "dependencies": { 774 | "rimraf": { 775 | "version": "2.6.3", 776 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 777 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 778 | "dev": true, 779 | "requires": { 780 | "glob": "^7.1.3" 781 | } 782 | } 783 | } 784 | }, 785 | "flatted": { 786 | "version": "2.0.2", 787 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", 788 | "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", 789 | "dev": true 790 | }, 791 | "fs.realpath": { 792 | "version": "1.0.0", 793 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 794 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 795 | "dev": true 796 | }, 797 | "fsevents": { 798 | "version": "2.1.3", 799 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 800 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 801 | "dev": true, 802 | "optional": true 803 | }, 804 | "function-bind": { 805 | "version": "1.1.1", 806 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 807 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 808 | "dev": true 809 | }, 810 | "functional-red-black-tree": { 811 | "version": "1.0.1", 812 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 813 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 814 | "dev": true 815 | }, 816 | "get-caller-file": { 817 | "version": "2.0.5", 818 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 819 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 820 | "dev": true 821 | }, 822 | "glob": { 823 | "version": "7.1.6", 824 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 825 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 826 | "dev": true, 827 | "requires": { 828 | "fs.realpath": "^1.0.0", 829 | "inflight": "^1.0.4", 830 | "inherits": "2", 831 | "minimatch": "^3.0.4", 832 | "once": "^1.3.0", 833 | "path-is-absolute": "^1.0.0" 834 | } 835 | }, 836 | "glob-parent": { 837 | "version": "5.1.1", 838 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 839 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 840 | "dev": true, 841 | "requires": { 842 | "is-glob": "^4.0.1" 843 | } 844 | }, 845 | "globals": { 846 | "version": "12.4.0", 847 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 848 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 849 | "dev": true, 850 | "requires": { 851 | "type-fest": "^0.8.1" 852 | } 853 | }, 854 | "growl": { 855 | "version": "1.10.5", 856 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 857 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 858 | "dev": true 859 | }, 860 | "has": { 861 | "version": "1.0.3", 862 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 863 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 864 | "dev": true, 865 | "requires": { 866 | "function-bind": "^1.1.1" 867 | } 868 | }, 869 | "has-flag": { 870 | "version": "3.0.0", 871 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 872 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 873 | "dev": true 874 | }, 875 | "has-symbols": { 876 | "version": "1.0.1", 877 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 878 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 879 | "dev": true 880 | }, 881 | "he": { 882 | "version": "1.2.0", 883 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 884 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 885 | "dev": true 886 | }, 887 | "http-proxy-agent": { 888 | "version": "2.1.0", 889 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", 890 | "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", 891 | "dev": true, 892 | "requires": { 893 | "agent-base": "4", 894 | "debug": "3.1.0" 895 | } 896 | }, 897 | "https-proxy-agent": { 898 | "version": "2.2.4", 899 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", 900 | "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", 901 | "dev": true, 902 | "requires": { 903 | "agent-base": "^4.3.0", 904 | "debug": "^3.1.0" 905 | } 906 | }, 907 | "iconv-lite": { 908 | "version": "0.4.24", 909 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 910 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 911 | "dev": true, 912 | "requires": { 913 | "safer-buffer": ">= 2.1.2 < 3" 914 | } 915 | }, 916 | "ignore": { 917 | "version": "4.0.6", 918 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 919 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 920 | "dev": true 921 | }, 922 | "import-fresh": { 923 | "version": "3.2.1", 924 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", 925 | "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", 926 | "dev": true, 927 | "requires": { 928 | "parent-module": "^1.0.0", 929 | "resolve-from": "^4.0.0" 930 | } 931 | }, 932 | "imurmurhash": { 933 | "version": "0.1.4", 934 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 935 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 936 | "dev": true 937 | }, 938 | "inflight": { 939 | "version": "1.0.6", 940 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 941 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 942 | "dev": true, 943 | "requires": { 944 | "once": "^1.3.0", 945 | "wrappy": "1" 946 | } 947 | }, 948 | "inherits": { 949 | "version": "2.0.4", 950 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 951 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 952 | "dev": true 953 | }, 954 | "inquirer": { 955 | "version": "7.3.2", 956 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.2.tgz", 957 | "integrity": "sha512-DF4osh1FM6l0RJc5YWYhSDB6TawiBRlbV9Cox8MWlidU218Tb7fm3lQTULyUJDfJ0tjbzl0W4q651mrCCEM55w==", 958 | "dev": true, 959 | "requires": { 960 | "ansi-escapes": "^4.2.1", 961 | "chalk": "^4.1.0", 962 | "cli-cursor": "^3.1.0", 963 | "cli-width": "^3.0.0", 964 | "external-editor": "^3.0.3", 965 | "figures": "^3.0.0", 966 | "lodash": "^4.17.16", 967 | "mute-stream": "0.0.8", 968 | "run-async": "^2.4.0", 969 | "rxjs": "^6.6.0", 970 | "string-width": "^4.1.0", 971 | "strip-ansi": "^6.0.0", 972 | "through": "^2.3.6" 973 | }, 974 | "dependencies": { 975 | "ansi-styles": { 976 | "version": "4.2.1", 977 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", 978 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", 979 | "dev": true, 980 | "requires": { 981 | "@types/color-name": "^1.1.1", 982 | "color-convert": "^2.0.1" 983 | } 984 | }, 985 | "chalk": { 986 | "version": "4.1.0", 987 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 988 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 989 | "dev": true, 990 | "requires": { 991 | "ansi-styles": "^4.1.0", 992 | "supports-color": "^7.1.0" 993 | } 994 | }, 995 | "color-convert": { 996 | "version": "2.0.1", 997 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 998 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 999 | "dev": true, 1000 | "requires": { 1001 | "color-name": "~1.1.4" 1002 | } 1003 | }, 1004 | "color-name": { 1005 | "version": "1.1.4", 1006 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1007 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1008 | "dev": true 1009 | }, 1010 | "has-flag": { 1011 | "version": "4.0.0", 1012 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1013 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1014 | "dev": true 1015 | }, 1016 | "strip-ansi": { 1017 | "version": "6.0.0", 1018 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1019 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1020 | "dev": true, 1021 | "requires": { 1022 | "ansi-regex": "^5.0.0" 1023 | } 1024 | }, 1025 | "supports-color": { 1026 | "version": "7.1.0", 1027 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", 1028 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", 1029 | "dev": true, 1030 | "requires": { 1031 | "has-flag": "^4.0.0" 1032 | } 1033 | } 1034 | } 1035 | }, 1036 | "is-arguments": { 1037 | "version": "1.0.4", 1038 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", 1039 | "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", 1040 | "dev": true 1041 | }, 1042 | "is-binary-path": { 1043 | "version": "2.1.0", 1044 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1045 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1046 | "dev": true, 1047 | "requires": { 1048 | "binary-extensions": "^2.0.0" 1049 | } 1050 | }, 1051 | "is-buffer": { 1052 | "version": "2.0.4", 1053 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", 1054 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", 1055 | "dev": true 1056 | }, 1057 | "is-callable": { 1058 | "version": "1.2.0", 1059 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", 1060 | "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", 1061 | "dev": true 1062 | }, 1063 | "is-date-object": { 1064 | "version": "1.0.2", 1065 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 1066 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 1067 | "dev": true 1068 | }, 1069 | "is-extglob": { 1070 | "version": "2.1.1", 1071 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1072 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1073 | "dev": true 1074 | }, 1075 | "is-fullwidth-code-point": { 1076 | "version": "3.0.0", 1077 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1078 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1079 | "dev": true 1080 | }, 1081 | "is-glob": { 1082 | "version": "4.0.1", 1083 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1084 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1085 | "dev": true, 1086 | "requires": { 1087 | "is-extglob": "^2.1.1" 1088 | } 1089 | }, 1090 | "is-map": { 1091 | "version": "2.0.1", 1092 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", 1093 | "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", 1094 | "dev": true 1095 | }, 1096 | "is-number": { 1097 | "version": "7.0.0", 1098 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1099 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1100 | "dev": true 1101 | }, 1102 | "is-regex": { 1103 | "version": "1.1.0", 1104 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", 1105 | "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", 1106 | "dev": true, 1107 | "requires": { 1108 | "has-symbols": "^1.0.1" 1109 | } 1110 | }, 1111 | "is-set": { 1112 | "version": "2.0.1", 1113 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", 1114 | "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", 1115 | "dev": true 1116 | }, 1117 | "is-string": { 1118 | "version": "1.0.5", 1119 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", 1120 | "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", 1121 | "dev": true 1122 | }, 1123 | "is-symbol": { 1124 | "version": "1.0.3", 1125 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 1126 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 1127 | "dev": true, 1128 | "requires": { 1129 | "has-symbols": "^1.0.1" 1130 | } 1131 | }, 1132 | "isarray": { 1133 | "version": "2.0.5", 1134 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", 1135 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", 1136 | "dev": true 1137 | }, 1138 | "isexe": { 1139 | "version": "2.0.0", 1140 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1141 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1142 | "dev": true 1143 | }, 1144 | "iterate-iterator": { 1145 | "version": "1.0.1", 1146 | "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", 1147 | "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", 1148 | "dev": true 1149 | }, 1150 | "iterate-value": { 1151 | "version": "1.0.2", 1152 | "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", 1153 | "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", 1154 | "dev": true, 1155 | "requires": { 1156 | "es-get-iterator": "^1.0.2", 1157 | "iterate-iterator": "^1.0.1" 1158 | } 1159 | }, 1160 | "js-tokens": { 1161 | "version": "4.0.0", 1162 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1163 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1164 | "dev": true 1165 | }, 1166 | "js-yaml": { 1167 | "version": "3.14.0", 1168 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", 1169 | "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", 1170 | "dev": true, 1171 | "requires": { 1172 | "argparse": "^1.0.7", 1173 | "esprima": "^4.0.0" 1174 | } 1175 | }, 1176 | "json-schema-traverse": { 1177 | "version": "0.4.1", 1178 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1179 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1180 | "dev": true 1181 | }, 1182 | "json-stable-stringify-without-jsonify": { 1183 | "version": "1.0.1", 1184 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1185 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1186 | "dev": true 1187 | }, 1188 | "levn": { 1189 | "version": "0.3.0", 1190 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1191 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1192 | "dev": true, 1193 | "requires": { 1194 | "prelude-ls": "~1.1.2", 1195 | "type-check": "~0.3.2" 1196 | } 1197 | }, 1198 | "locate-path": { 1199 | "version": "5.0.0", 1200 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1201 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1202 | "dev": true, 1203 | "requires": { 1204 | "p-locate": "^4.1.0" 1205 | } 1206 | }, 1207 | "lodash": { 1208 | "version": "4.17.19", 1209 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", 1210 | "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", 1211 | "dev": true 1212 | }, 1213 | "log-symbols": { 1214 | "version": "3.0.0", 1215 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", 1216 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", 1217 | "dev": true, 1218 | "requires": { 1219 | "chalk": "^2.4.2" 1220 | } 1221 | }, 1222 | "mimic-fn": { 1223 | "version": "2.1.0", 1224 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 1225 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 1226 | "dev": true 1227 | }, 1228 | "minimatch": { 1229 | "version": "3.0.4", 1230 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1231 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1232 | "dev": true, 1233 | "requires": { 1234 | "brace-expansion": "^1.1.7" 1235 | } 1236 | }, 1237 | "minimist": { 1238 | "version": "1.2.5", 1239 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 1240 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 1241 | "dev": true 1242 | }, 1243 | "mkdirp": { 1244 | "version": "0.5.5", 1245 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 1246 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 1247 | "dev": true, 1248 | "requires": { 1249 | "minimist": "^1.2.5" 1250 | } 1251 | }, 1252 | "mocha": { 1253 | "version": "8.0.1", 1254 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", 1255 | "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", 1256 | "dev": true, 1257 | "requires": { 1258 | "ansi-colors": "4.1.1", 1259 | "browser-stdout": "1.3.1", 1260 | "chokidar": "3.3.1", 1261 | "debug": "3.2.6", 1262 | "diff": "4.0.2", 1263 | "escape-string-regexp": "1.0.5", 1264 | "find-up": "4.1.0", 1265 | "glob": "7.1.6", 1266 | "growl": "1.10.5", 1267 | "he": "1.2.0", 1268 | "js-yaml": "3.13.1", 1269 | "log-symbols": "3.0.0", 1270 | "minimatch": "3.0.4", 1271 | "ms": "2.1.2", 1272 | "object.assign": "4.1.0", 1273 | "promise.allsettled": "1.0.2", 1274 | "serialize-javascript": "3.0.0", 1275 | "strip-json-comments": "3.0.1", 1276 | "supports-color": "7.1.0", 1277 | "which": "2.0.2", 1278 | "wide-align": "1.1.3", 1279 | "workerpool": "6.0.0", 1280 | "yargs": "13.3.2", 1281 | "yargs-parser": "13.1.2", 1282 | "yargs-unparser": "1.6.0" 1283 | }, 1284 | "dependencies": { 1285 | "debug": { 1286 | "version": "3.2.6", 1287 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1288 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 1289 | "dev": true, 1290 | "requires": { 1291 | "ms": "^2.1.1" 1292 | } 1293 | }, 1294 | "has-flag": { 1295 | "version": "4.0.0", 1296 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1297 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1298 | "dev": true 1299 | }, 1300 | "js-yaml": { 1301 | "version": "3.13.1", 1302 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 1303 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 1304 | "dev": true, 1305 | "requires": { 1306 | "argparse": "^1.0.7", 1307 | "esprima": "^4.0.0" 1308 | } 1309 | }, 1310 | "ms": { 1311 | "version": "2.1.2", 1312 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1313 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1314 | "dev": true 1315 | }, 1316 | "strip-json-comments": { 1317 | "version": "3.0.1", 1318 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", 1319 | "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", 1320 | "dev": true 1321 | }, 1322 | "supports-color": { 1323 | "version": "7.1.0", 1324 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", 1325 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", 1326 | "dev": true, 1327 | "requires": { 1328 | "has-flag": "^4.0.0" 1329 | } 1330 | }, 1331 | "which": { 1332 | "version": "2.0.2", 1333 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1334 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1335 | "dev": true, 1336 | "requires": { 1337 | "isexe": "^2.0.0" 1338 | } 1339 | } 1340 | } 1341 | }, 1342 | "ms": { 1343 | "version": "2.0.0", 1344 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1345 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1346 | "dev": true 1347 | }, 1348 | "mute-stream": { 1349 | "version": "0.0.8", 1350 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", 1351 | "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", 1352 | "dev": true 1353 | }, 1354 | "natural-compare": { 1355 | "version": "1.4.0", 1356 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1357 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1358 | "dev": true 1359 | }, 1360 | "nice-try": { 1361 | "version": "1.0.5", 1362 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 1363 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 1364 | "dev": true 1365 | }, 1366 | "normalize-path": { 1367 | "version": "3.0.0", 1368 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1369 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1370 | "dev": true 1371 | }, 1372 | "object-inspect": { 1373 | "version": "1.8.0", 1374 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", 1375 | "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", 1376 | "dev": true 1377 | }, 1378 | "object-keys": { 1379 | "version": "1.1.1", 1380 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1381 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1382 | "dev": true 1383 | }, 1384 | "object.assign": { 1385 | "version": "4.1.0", 1386 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 1387 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 1388 | "dev": true, 1389 | "requires": { 1390 | "define-properties": "^1.1.2", 1391 | "function-bind": "^1.1.1", 1392 | "has-symbols": "^1.0.0", 1393 | "object-keys": "^1.0.11" 1394 | } 1395 | }, 1396 | "once": { 1397 | "version": "1.4.0", 1398 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1399 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1400 | "dev": true, 1401 | "requires": { 1402 | "wrappy": "1" 1403 | } 1404 | }, 1405 | "onetime": { 1406 | "version": "5.1.0", 1407 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", 1408 | "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", 1409 | "dev": true, 1410 | "requires": { 1411 | "mimic-fn": "^2.1.0" 1412 | } 1413 | }, 1414 | "optionator": { 1415 | "version": "0.8.3", 1416 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", 1417 | "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", 1418 | "dev": true, 1419 | "requires": { 1420 | "deep-is": "~0.1.3", 1421 | "fast-levenshtein": "~2.0.6", 1422 | "levn": "~0.3.0", 1423 | "prelude-ls": "~1.1.2", 1424 | "type-check": "~0.3.2", 1425 | "word-wrap": "~1.2.3" 1426 | } 1427 | }, 1428 | "os-tmpdir": { 1429 | "version": "1.0.2", 1430 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1431 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1432 | "dev": true 1433 | }, 1434 | "p-limit": { 1435 | "version": "2.3.0", 1436 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1437 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1438 | "dev": true, 1439 | "requires": { 1440 | "p-try": "^2.0.0" 1441 | } 1442 | }, 1443 | "p-locate": { 1444 | "version": "4.1.0", 1445 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1446 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1447 | "dev": true, 1448 | "requires": { 1449 | "p-limit": "^2.2.0" 1450 | } 1451 | }, 1452 | "p-try": { 1453 | "version": "2.2.0", 1454 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 1455 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 1456 | "dev": true 1457 | }, 1458 | "parent-module": { 1459 | "version": "1.0.1", 1460 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1461 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1462 | "dev": true, 1463 | "requires": { 1464 | "callsites": "^3.0.0" 1465 | } 1466 | }, 1467 | "path-exists": { 1468 | "version": "4.0.0", 1469 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1470 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1471 | "dev": true 1472 | }, 1473 | "path-is-absolute": { 1474 | "version": "1.0.1", 1475 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1476 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1477 | "dev": true 1478 | }, 1479 | "path-key": { 1480 | "version": "2.0.1", 1481 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1482 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1483 | "dev": true 1484 | }, 1485 | "picomatch": { 1486 | "version": "2.2.2", 1487 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 1488 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 1489 | "dev": true 1490 | }, 1491 | "prelude-ls": { 1492 | "version": "1.1.2", 1493 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1494 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1495 | "dev": true 1496 | }, 1497 | "progress": { 1498 | "version": "2.0.3", 1499 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1500 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1501 | "dev": true 1502 | }, 1503 | "promise.allsettled": { 1504 | "version": "1.0.2", 1505 | "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", 1506 | "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", 1507 | "dev": true, 1508 | "requires": { 1509 | "array.prototype.map": "^1.0.1", 1510 | "define-properties": "^1.1.3", 1511 | "es-abstract": "^1.17.0-next.1", 1512 | "function-bind": "^1.1.1", 1513 | "iterate-value": "^1.0.0" 1514 | } 1515 | }, 1516 | "punycode": { 1517 | "version": "2.1.1", 1518 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1519 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1520 | "dev": true 1521 | }, 1522 | "readdirp": { 1523 | "version": "3.3.0", 1524 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", 1525 | "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", 1526 | "dev": true, 1527 | "requires": { 1528 | "picomatch": "^2.0.7" 1529 | } 1530 | }, 1531 | "regexpp": { 1532 | "version": "2.0.1", 1533 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 1534 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 1535 | "dev": true 1536 | }, 1537 | "require-directory": { 1538 | "version": "2.1.1", 1539 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1540 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1541 | "dev": true 1542 | }, 1543 | "require-main-filename": { 1544 | "version": "2.0.0", 1545 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", 1546 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", 1547 | "dev": true 1548 | }, 1549 | "resolve-from": { 1550 | "version": "4.0.0", 1551 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1552 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1553 | "dev": true 1554 | }, 1555 | "restore-cursor": { 1556 | "version": "3.1.0", 1557 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", 1558 | "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", 1559 | "dev": true, 1560 | "requires": { 1561 | "onetime": "^5.1.0", 1562 | "signal-exit": "^3.0.2" 1563 | } 1564 | }, 1565 | "rimraf": { 1566 | "version": "2.7.1", 1567 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1568 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1569 | "dev": true, 1570 | "requires": { 1571 | "glob": "^7.1.3" 1572 | } 1573 | }, 1574 | "run-async": { 1575 | "version": "2.4.1", 1576 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", 1577 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", 1578 | "dev": true 1579 | }, 1580 | "rxjs": { 1581 | "version": "6.6.0", 1582 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", 1583 | "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", 1584 | "dev": true, 1585 | "requires": { 1586 | "tslib": "^1.9.0" 1587 | } 1588 | }, 1589 | "safer-buffer": { 1590 | "version": "2.1.2", 1591 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1592 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1593 | "dev": true 1594 | }, 1595 | "semver": { 1596 | "version": "7.3.2", 1597 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", 1598 | "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", 1599 | "dev": true 1600 | }, 1601 | "serialize-javascript": { 1602 | "version": "3.0.0", 1603 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", 1604 | "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", 1605 | "dev": true 1606 | }, 1607 | "set-blocking": { 1608 | "version": "2.0.0", 1609 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 1610 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 1611 | "dev": true 1612 | }, 1613 | "shebang-command": { 1614 | "version": "1.2.0", 1615 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1616 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1617 | "dev": true, 1618 | "requires": { 1619 | "shebang-regex": "^1.0.0" 1620 | } 1621 | }, 1622 | "shebang-regex": { 1623 | "version": "1.0.0", 1624 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1625 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1626 | "dev": true 1627 | }, 1628 | "signal-exit": { 1629 | "version": "3.0.3", 1630 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1631 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 1632 | "dev": true 1633 | }, 1634 | "slice-ansi": { 1635 | "version": "2.1.0", 1636 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 1637 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 1638 | "dev": true, 1639 | "requires": { 1640 | "ansi-styles": "^3.2.0", 1641 | "astral-regex": "^1.0.0", 1642 | "is-fullwidth-code-point": "^2.0.0" 1643 | }, 1644 | "dependencies": { 1645 | "is-fullwidth-code-point": { 1646 | "version": "2.0.0", 1647 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1648 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1649 | "dev": true 1650 | } 1651 | } 1652 | }, 1653 | "sprintf-js": { 1654 | "version": "1.0.3", 1655 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1656 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1657 | "dev": true 1658 | }, 1659 | "string-width": { 1660 | "version": "4.2.0", 1661 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1662 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1663 | "dev": true, 1664 | "requires": { 1665 | "emoji-regex": "^8.0.0", 1666 | "is-fullwidth-code-point": "^3.0.0", 1667 | "strip-ansi": "^6.0.0" 1668 | }, 1669 | "dependencies": { 1670 | "strip-ansi": { 1671 | "version": "6.0.0", 1672 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1673 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1674 | "dev": true, 1675 | "requires": { 1676 | "ansi-regex": "^5.0.0" 1677 | } 1678 | } 1679 | } 1680 | }, 1681 | "string.prototype.trimend": { 1682 | "version": "1.0.1", 1683 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", 1684 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", 1685 | "dev": true, 1686 | "requires": { 1687 | "define-properties": "^1.1.3", 1688 | "es-abstract": "^1.17.5" 1689 | } 1690 | }, 1691 | "string.prototype.trimstart": { 1692 | "version": "1.0.1", 1693 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 1694 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", 1695 | "dev": true, 1696 | "requires": { 1697 | "define-properties": "^1.1.3", 1698 | "es-abstract": "^1.17.5" 1699 | } 1700 | }, 1701 | "strip-ansi": { 1702 | "version": "5.2.0", 1703 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1704 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1705 | "dev": true, 1706 | "requires": { 1707 | "ansi-regex": "^4.1.0" 1708 | }, 1709 | "dependencies": { 1710 | "ansi-regex": { 1711 | "version": "4.1.0", 1712 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1713 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1714 | "dev": true 1715 | } 1716 | } 1717 | }, 1718 | "strip-json-comments": { 1719 | "version": "3.1.1", 1720 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1721 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1722 | "dev": true 1723 | }, 1724 | "supports-color": { 1725 | "version": "5.5.0", 1726 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1727 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1728 | "dev": true, 1729 | "requires": { 1730 | "has-flag": "^3.0.0" 1731 | } 1732 | }, 1733 | "table": { 1734 | "version": "5.4.6", 1735 | "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", 1736 | "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", 1737 | "dev": true, 1738 | "requires": { 1739 | "ajv": "^6.10.2", 1740 | "lodash": "^4.17.14", 1741 | "slice-ansi": "^2.1.0", 1742 | "string-width": "^3.0.0" 1743 | }, 1744 | "dependencies": { 1745 | "emoji-regex": { 1746 | "version": "7.0.3", 1747 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 1748 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 1749 | "dev": true 1750 | }, 1751 | "is-fullwidth-code-point": { 1752 | "version": "2.0.0", 1753 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1754 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1755 | "dev": true 1756 | }, 1757 | "string-width": { 1758 | "version": "3.1.0", 1759 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1760 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1761 | "dev": true, 1762 | "requires": { 1763 | "emoji-regex": "^7.0.1", 1764 | "is-fullwidth-code-point": "^2.0.0", 1765 | "strip-ansi": "^5.1.0" 1766 | } 1767 | } 1768 | } 1769 | }, 1770 | "text-table": { 1771 | "version": "0.2.0", 1772 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1773 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1774 | "dev": true 1775 | }, 1776 | "through": { 1777 | "version": "2.3.8", 1778 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1779 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1780 | "dev": true 1781 | }, 1782 | "tmp": { 1783 | "version": "0.0.33", 1784 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1785 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1786 | "dev": true, 1787 | "requires": { 1788 | "os-tmpdir": "~1.0.2" 1789 | } 1790 | }, 1791 | "to-regex-range": { 1792 | "version": "5.0.1", 1793 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1794 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1795 | "dev": true, 1796 | "requires": { 1797 | "is-number": "^7.0.0" 1798 | } 1799 | }, 1800 | "tslib": { 1801 | "version": "1.13.0", 1802 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", 1803 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", 1804 | "dev": true 1805 | }, 1806 | "tsutils": { 1807 | "version": "3.17.1", 1808 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", 1809 | "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", 1810 | "dev": true, 1811 | "requires": { 1812 | "tslib": "^1.8.1" 1813 | } 1814 | }, 1815 | "type-check": { 1816 | "version": "0.3.2", 1817 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1818 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1819 | "dev": true, 1820 | "requires": { 1821 | "prelude-ls": "~1.1.2" 1822 | } 1823 | }, 1824 | "type-fest": { 1825 | "version": "0.8.1", 1826 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 1827 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 1828 | "dev": true 1829 | }, 1830 | "typescript": { 1831 | "version": "3.9.7", 1832 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", 1833 | "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", 1834 | "dev": true 1835 | }, 1836 | "uri-js": { 1837 | "version": "4.2.2", 1838 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1839 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1840 | "dev": true, 1841 | "requires": { 1842 | "punycode": "^2.1.0" 1843 | } 1844 | }, 1845 | "v8-compile-cache": { 1846 | "version": "2.1.1", 1847 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", 1848 | "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", 1849 | "dev": true 1850 | }, 1851 | "vscode-jsonrpc": { 1852 | "version": "5.0.1", 1853 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", 1854 | "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==" 1855 | }, 1856 | "vscode-languageclient": { 1857 | "version": "6.1.3", 1858 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.3.tgz", 1859 | "integrity": "sha512-YciJxk08iU5LmWu7j5dUt9/1OLjokKET6rME3cI4BRpiF6HZlusm2ZwPt0MYJ0lV5y43sZsQHhyon2xBg4ZJVA==", 1860 | "requires": { 1861 | "semver": "^6.3.0", 1862 | "vscode-languageserver-protocol": "^3.15.3" 1863 | }, 1864 | "dependencies": { 1865 | "semver": { 1866 | "version": "6.3.0", 1867 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1868 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 1869 | } 1870 | } 1871 | }, 1872 | "vscode-languageserver-protocol": { 1873 | "version": "3.15.3", 1874 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", 1875 | "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", 1876 | "requires": { 1877 | "vscode-jsonrpc": "^5.0.1", 1878 | "vscode-languageserver-types": "3.15.1" 1879 | } 1880 | }, 1881 | "vscode-languageserver-types": { 1882 | "version": "3.15.1", 1883 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", 1884 | "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" 1885 | }, 1886 | "vscode-test": { 1887 | "version": "1.3.0", 1888 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", 1889 | "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", 1890 | "dev": true, 1891 | "requires": { 1892 | "http-proxy-agent": "^2.1.0", 1893 | "https-proxy-agent": "^2.2.4", 1894 | "rimraf": "^2.6.3" 1895 | } 1896 | }, 1897 | "which": { 1898 | "version": "1.3.1", 1899 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1900 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1901 | "dev": true, 1902 | "requires": { 1903 | "isexe": "^2.0.0" 1904 | } 1905 | }, 1906 | "which-module": { 1907 | "version": "2.0.0", 1908 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 1909 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 1910 | "dev": true 1911 | }, 1912 | "wide-align": { 1913 | "version": "1.1.3", 1914 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 1915 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 1916 | "dev": true, 1917 | "requires": { 1918 | "string-width": "^1.0.2 || 2" 1919 | }, 1920 | "dependencies": { 1921 | "ansi-regex": { 1922 | "version": "3.0.0", 1923 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1924 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1925 | "dev": true 1926 | }, 1927 | "is-fullwidth-code-point": { 1928 | "version": "2.0.0", 1929 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1930 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1931 | "dev": true 1932 | }, 1933 | "string-width": { 1934 | "version": "2.1.1", 1935 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1936 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1937 | "dev": true, 1938 | "requires": { 1939 | "is-fullwidth-code-point": "^2.0.0", 1940 | "strip-ansi": "^4.0.0" 1941 | } 1942 | }, 1943 | "strip-ansi": { 1944 | "version": "4.0.0", 1945 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1946 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1947 | "dev": true, 1948 | "requires": { 1949 | "ansi-regex": "^3.0.0" 1950 | } 1951 | } 1952 | } 1953 | }, 1954 | "word-wrap": { 1955 | "version": "1.2.3", 1956 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1957 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1958 | "dev": true 1959 | }, 1960 | "workerpool": { 1961 | "version": "6.0.0", 1962 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", 1963 | "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", 1964 | "dev": true 1965 | }, 1966 | "wrap-ansi": { 1967 | "version": "5.1.0", 1968 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 1969 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 1970 | "dev": true, 1971 | "requires": { 1972 | "ansi-styles": "^3.2.0", 1973 | "string-width": "^3.0.0", 1974 | "strip-ansi": "^5.0.0" 1975 | }, 1976 | "dependencies": { 1977 | "emoji-regex": { 1978 | "version": "7.0.3", 1979 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 1980 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 1981 | "dev": true 1982 | }, 1983 | "is-fullwidth-code-point": { 1984 | "version": "2.0.0", 1985 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1986 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1987 | "dev": true 1988 | }, 1989 | "string-width": { 1990 | "version": "3.1.0", 1991 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1992 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1993 | "dev": true, 1994 | "requires": { 1995 | "emoji-regex": "^7.0.1", 1996 | "is-fullwidth-code-point": "^2.0.0", 1997 | "strip-ansi": "^5.1.0" 1998 | } 1999 | } 2000 | } 2001 | }, 2002 | "wrappy": { 2003 | "version": "1.0.2", 2004 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2005 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2006 | "dev": true 2007 | }, 2008 | "write": { 2009 | "version": "1.0.3", 2010 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 2011 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 2012 | "dev": true, 2013 | "requires": { 2014 | "mkdirp": "^0.5.1" 2015 | } 2016 | }, 2017 | "y18n": { 2018 | "version": "4.0.0", 2019 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 2020 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 2021 | "dev": true 2022 | }, 2023 | "yargs": { 2024 | "version": "13.3.2", 2025 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", 2026 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", 2027 | "dev": true, 2028 | "requires": { 2029 | "cliui": "^5.0.0", 2030 | "find-up": "^3.0.0", 2031 | "get-caller-file": "^2.0.1", 2032 | "require-directory": "^2.1.1", 2033 | "require-main-filename": "^2.0.0", 2034 | "set-blocking": "^2.0.0", 2035 | "string-width": "^3.0.0", 2036 | "which-module": "^2.0.0", 2037 | "y18n": "^4.0.0", 2038 | "yargs-parser": "^13.1.2" 2039 | }, 2040 | "dependencies": { 2041 | "emoji-regex": { 2042 | "version": "7.0.3", 2043 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 2044 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 2045 | "dev": true 2046 | }, 2047 | "find-up": { 2048 | "version": "3.0.0", 2049 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 2050 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 2051 | "dev": true, 2052 | "requires": { 2053 | "locate-path": "^3.0.0" 2054 | } 2055 | }, 2056 | "is-fullwidth-code-point": { 2057 | "version": "2.0.0", 2058 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 2059 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 2060 | "dev": true 2061 | }, 2062 | "locate-path": { 2063 | "version": "3.0.0", 2064 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 2065 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 2066 | "dev": true, 2067 | "requires": { 2068 | "p-locate": "^3.0.0", 2069 | "path-exists": "^3.0.0" 2070 | } 2071 | }, 2072 | "p-locate": { 2073 | "version": "3.0.0", 2074 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 2075 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 2076 | "dev": true, 2077 | "requires": { 2078 | "p-limit": "^2.0.0" 2079 | } 2080 | }, 2081 | "path-exists": { 2082 | "version": "3.0.0", 2083 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 2084 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 2085 | "dev": true 2086 | }, 2087 | "string-width": { 2088 | "version": "3.1.0", 2089 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 2090 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 2091 | "dev": true, 2092 | "requires": { 2093 | "emoji-regex": "^7.0.1", 2094 | "is-fullwidth-code-point": "^2.0.0", 2095 | "strip-ansi": "^5.1.0" 2096 | } 2097 | } 2098 | } 2099 | }, 2100 | "yargs-parser": { 2101 | "version": "13.1.2", 2102 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", 2103 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", 2104 | "dev": true, 2105 | "requires": { 2106 | "camelcase": "^5.0.0", 2107 | "decamelize": "^1.2.0" 2108 | } 2109 | }, 2110 | "yargs-unparser": { 2111 | "version": "1.6.0", 2112 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", 2113 | "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", 2114 | "dev": true, 2115 | "requires": { 2116 | "flat": "^4.1.0", 2117 | "lodash": "^4.17.15", 2118 | "yargs": "^13.3.0" 2119 | } 2120 | } 2121 | } 2122 | } 2123 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sml-analyzer-client", 3 | "description": "VSCode extension for sml-analyzer", 4 | "author": "Michael Lazear", 5 | "license": "MIT", 6 | "version": "0.0.1", 7 | "publisher": "vscode", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/lazear/sml-analyzer" 11 | }, 12 | "engines": { 13 | "vscode": "^1.43.0" 14 | }, 15 | "activationEvents": [ 16 | "onLanguage:sml" 17 | ], 18 | "main": "./out/extension", 19 | "dependencies": { 20 | "vscode-languageclient": "^6.1.3" 21 | }, 22 | "contributes": { 23 | "languages": [ 24 | { 25 | "id": "sml", 26 | "extensions": [ 27 | ".sml", 28 | ".fun", 29 | ".sig" 30 | ], 31 | "aliases": [ 32 | "Standard ML", 33 | "sml" 34 | ] 35 | } 36 | ], 37 | "grammars": [ 38 | { 39 | "language": "sml", 40 | "scopeName": "source.sml", 41 | "path": "./syntaxes/sml.tmLanguage.json" 42 | } 43 | ] 44 | }, 45 | "devDependencies": { 46 | "@types/vscode": "1.43.0", 47 | "vscode-test": "^1.3.0", 48 | "@types/mocha": "^7.0.2", 49 | "mocha": "^8.0.1", 50 | "@types/node": "^12.12.0", 51 | "eslint": "^6.4.0", 52 | "@typescript-eslint/parser": "^2.3.0", 53 | "typescript": "^3.9.4" 54 | }, 55 | "scripts": { 56 | "vscode:prepublish": "npm run compile", 57 | "compile": "tsc -b", 58 | "watch": "tsc -b -w" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | 6 | import * as path from 'path'; 7 | import { workspace, ExtensionContext, TextDocument, Range, } from 'vscode'; 8 | 9 | import { 10 | LanguageClient, 11 | LanguageClientOptions, 12 | ServerOptions, 13 | TransportKind, 14 | Executable, 15 | VersionedTextDocumentIdentifier, 16 | CodeLens, 17 | CancellationToken, 18 | ProvideCodeLensesSignature, 19 | NotificationType, 20 | MessageType, 21 | } from 'vscode-languageclient'; 22 | 23 | let client: LanguageClient; 24 | 25 | export function activate(context: ExtensionContext) { 26 | // The server is implemented in node 27 | let cwd = "."; 28 | let command = path.join(context.extensionPath, "target", "debug", "sml-analyzer.exe"); 29 | const run: Executable = { 30 | command, 31 | options: { cwd }, 32 | }; 33 | 34 | // The debug options for the server 35 | // --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging 36 | let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; 37 | 38 | // If the extension is launched in debug mode then the debug server options are used 39 | // Otherwise the run options are used 40 | let serverOptions: ServerOptions = { 41 | run, 42 | debug: run 43 | }; 44 | 45 | // Options to control the language client 46 | let clientOptions: LanguageClientOptions = { 47 | // Register the server for plain text documents 48 | documentSelector: [{ scheme: 'file', language: 'sml' }], 49 | synchronize: { 50 | // Notify the server about file changes to '.clientrc files contained in the workspace 51 | fileEvents: workspace.createFileSystemWatcher('**/.clientrc') 52 | }, 53 | // middleware: { 54 | // async provideCodeLenses(document: TextDocument, token: CancellationToken, next: ProvideCodeLensesSignature) { 55 | // var items = []; 56 | // // CodeLens { 57 | // // range: Range { 58 | 59 | // // } 60 | // // } 61 | // // client.sendNotification(MessageType.Info()) 62 | // return client.protocol2CodeConverter.asCodeLenses(items) 63 | // } 64 | // } 65 | }; 66 | 67 | 68 | // Create the language client and start the client. 69 | client = new LanguageClient( 70 | 'sml-analyzer', 71 | 'SomewhatML server', 72 | serverOptions, 73 | clientOptions 74 | ); 75 | 76 | // Start the client. This will also launch the server 77 | client.start(); 78 | } 79 | 80 | export function deactivate(): Thenable | undefined { 81 | if (!client) { 82 | return undefined; 83 | } 84 | return client.stop(); 85 | } 86 | -------------------------------------------------------------------------------- /syntaxes/sml.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "Standard ML", 4 | "patterns": [ 5 | { "include": "#decDec" }, 6 | { "include": "#exp "}, 7 | { "include": "#number" }, 8 | { "include": "#strings" }, 9 | { "include": "#comment" }, 10 | { "include": "#const" }, 11 | { "include": "#keywords" }, 12 | { "include": "#typeVar" } 13 | ], 14 | "repository": { 15 | "decDec": { 16 | "patterns": [ 17 | { 18 | "match": "\\s*(structure)\\s+(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-])\\s*:>?\\s*(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]|$)", 19 | "captures": { 20 | "1": { "name": "keyword.other.sml" }, 21 | "2": { "name": "support.variable.sml" }, 22 | "3": { "name": "entity.name.type.sml" } 23 | } 24 | }, 25 | { 26 | "match": "\\s*(structure)\\s+(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]|$)", 27 | "captures": { 28 | "1": { "name": "keyword.other.sml" }, 29 | "2": { "name": "support.variable.sml" } 30 | } 31 | }, 32 | { 33 | "match": "\\s*(signature)\\s+(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]|$)", 34 | "captures": { 35 | "1": { "name": "keyword.other.sml" }, 36 | "2": { "name": "entity.name.type.sml" } 37 | } 38 | }, 39 | { 40 | "match": "\\s*(exception)\\s+(op)?(.*?)(?:\\s|$)", 41 | "captures": { 42 | "1": { "name": "keyword.other.sml" }, 43 | "2": { "name": "keyword.other.sml" }, 44 | "3": { "name": "entity.name.type.sml" } 45 | } 46 | }, 47 | { 48 | "match": "\\s*(datatype)\\s+(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]|$)", 49 | "captures": { 50 | "1": { "name": "keyword.other.sml" }, 51 | "2": { "name": "entity.name.type.sml" } 52 | } 53 | }, 54 | { 55 | "match": "(fun)\\s+(op)?([a-zA-Z_][a-zA-Z0-9'_!%&$#+/:<=>?@\\~`^|*-]*)", 56 | "captures": { 57 | "1": { "name": "keyword.other.sml" }, 58 | "2": { "name": "keyword.other.sml" }, 59 | "3": { "name": "entity.name.function.sml" } 60 | } 61 | }, 62 | { 63 | "match": "\\|\\s+(op)?([a-zA-Z_][a-zA-Z0-9'_!%&$#+/:<=>?@\\~`^|*-]*)", 64 | "captures": { 65 | "1": { "name": "keyword.other.sml" }, 66 | "2": { "name": "entity.name.function.sml" } 67 | } 68 | }, 69 | { 70 | "match": "\\b(val)\\s+(.*?)(?:[^a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]|$)", 71 | "captures": { 72 | "1": { "name": "keyword.other.sml" }, 73 | "2": { 74 | "patterns": [ 75 | { 76 | "match": "(op)([!%&$#+/:<=>?@\\~`^|*-]+)", 77 | "captures": { 78 | "1": { "name": "keyword.other.sml" }, 79 | "2": { "name": "keyword.operator.sml" } 80 | } 81 | }, 82 | { 83 | "name": "variable.other.sml", 84 | "match": ".*" 85 | } 86 | ] 87 | } 88 | } 89 | } 90 | ] 91 | }, 92 | "exp": { 93 | "patterns": [ 94 | { 95 | "match": "(raise)\\s+([a-zA-Z_][a-zA-Z0-9_!%&$#+/:<=>?@\\~`^|*-]*)", 96 | "captures": { 97 | "1": { "name": "keyword.control.sml" }, 98 | "2": { "name": "entity.name.type.sml" } 99 | } 100 | } 101 | ] 102 | }, 103 | "number": { 104 | "patterns": [ 105 | { 106 | "name": "constant.numeric.sml", 107 | "match": "(?:0w(?:\\d+|x[0-9a-fA-F]+)|~?0x[0-9a-fA-F]+|~?\\d+(?:\\.\\d+)?(?:[eE]~?\\d+)?)" 108 | } 109 | ] 110 | }, 111 | "keywords": { 112 | "patterns": [ 113 | { 114 | "name": "keyword.control.sml", 115 | "match": "\\b(if|then|else|case|of|raise|while|do|use)\\b" 116 | }, 117 | { 118 | "name": "keyword.other.sml", 119 | "match": "\\b(abstype|and|datatype|exception|op|fn|fun(?:ctor)?|handle|in|infixr?|let|local|nonfix|open|rec|type|val|with|withtype|end|sharing|where|include|sig(?:nature)?|eqtype|struct(?:ure)?)\\b" 120 | } 121 | ] 122 | }, 123 | "strings": { 124 | "name": "string.quoted.double.sml", 125 | "begin": "#?\"", 126 | "end": "\"", 127 | "patterns": [ 128 | { 129 | "name": "constant.character.escape.sml", 130 | "begin": "\\\\(?:\\s+|$)", 131 | "end": "(?:^|\\s+)\\\\", 132 | "patterns": [{ 133 | "match": "^\\s*$" 134 | }] 135 | }, 136 | { 137 | "name": "constant.character.escape.sml", 138 | "match": "\\\\(?:[abtnvfr]|\\d{3}|\"|\\s*\\\\)" 139 | } 140 | ] 141 | }, 142 | "comment": { 143 | "patterns": [{ 144 | "name": "comment.block.sml", 145 | "begin": "\\(\\*", 146 | "end": "\\*\\)", 147 | "patterns": [{"include": "#comment"}] 148 | }] 149 | }, 150 | "const": { 151 | "patterns": [ 152 | { 153 | "name": "constant.language.boolean.sml", 154 | "match": "\\b(true|false|nil|ref)\\b" 155 | }, 156 | { 157 | "name": "constant.language.exception.sml", 158 | "match": "\\b(Bind|Chr|Div|Domain|Empty|Fail|Match|Option|Overflow|Size|Span|Subscript)\\b" 159 | }, 160 | { 161 | "name": "entity.name.type.sml", 162 | "match": "\\b(unit|bool|int|word|real|string|char|list|ref|exn)\\b" 163 | }, 164 | { 165 | "name": "keyword.operator.sml", 166 | "match": "\\b(orelse|andalso|div|mod|\\+|-|\\*|\\\\|\\^|::|\\!|:=|@|~|abs|<|>|<=|>=|#|before|ignore|o)\\b" 167 | } 168 | ] 169 | }, 170 | "typeVar": { 171 | "patterns": [ 172 | { 173 | "name": "variable.parameter.type.sml", 174 | "match": "''?[a-fA-F]+" 175 | } 176 | ] 177 | } 178 | }, 179 | "scopeName": "source.sml" 180 | } -------------------------------------------------------------------------------- /test.sml: -------------------------------------------------------------------------------- 1 | fun test {x, y=10, ...} = 10 2 | | test {x, y=_, ...} = 12; 3 | 4 | val _ = test {x=10, y=12}; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2019", 5 | "lib": ["ES2019"], 6 | "outDir": "out", 7 | "rootDir": "src", 8 | "sourceMap": true 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules", ".vscode-test"] 12 | } 13 | --------------------------------------------------------------------------------