[rust] Expose parse function to napi
Updates the `forget_napi` crate to call the parser and semantic analyzer and convert their values to JS.
Joe Savona committed
Aug 21, 2023 at 16:04 UTC
9c13e4413c270da3acfbe0956a71fb90fc6c8475
4 files changed
+131
-10
compiler/forget/Cargo.lock
+5
@@ -285,9 +285,14 @@ dependencies = [
285
name = "forget_napi"
286
version = "0.1.0"
287
dependencies = [
288
+ "forget_diagnostics",
289
+ "forget_estree",
290
+ "forget_hermes_parser",
291
+ "forget_semantic_analysis",
292
"napi",
293
"napi-build",
294
"napi-derive",
295
+ "serde_json",
296
]
297
298
[[package]]
compiler/forget/crates/forget_napi/Cargo.toml
+5
@@ -14,8 +14,13 @@ repository.workspace = true
14
crate-type = ["cdylib"]
15
16
[dependencies]
17
+forget_diagnostics = { workspace = true }
18
+forget_hermes_parser = { workspace = true }
19
+forget_estree = { workspace = true }
20
+forget_semantic_analysis = { workspace = true }
21
napi = { version = "2.13.3", features = ["serde-json", "async"] }
22
napi-derive = { version = "2.12" }
23
+serde_json = { workspace = true }
24
25
[build-dependencies]
26
napi-build = "2"
\ No newline at end of file
compiler/forget/crates/forget_napi/README.md
new
+13
@@ -0,0 +1,13 @@
1
+# forget_napi
2
+
3
+This crate uses [napi-rs](https://napi.rs/) to expose Forget's analysis to JavaScript via the [Node-API](https://nodejs.org/api/n-api.html#node-api).
4
+
5
+## Build
6
+
7
+Note that `napi-rs` is a bit finicky and doesn't offer full control over where its outputs are emitted. For consistency, be sure to build with
8
+
9
+```
10
+yarn build
11
+```
12
+
13
+To use the canonical build, which will ensure that all files are placed in the right location.
\ No newline at end of file
compiler/forget/crates/forget_napi/src/lib.rs
+108
-10
@@ -1,17 +1,115 @@
1
+use forget_diagnostics::Diagnostic;
2
+use forget_semantic_analysis::{analyze, AnalyzeOptions};
3
use napi_derive::napi;
4
5
+pub const GLOBALS: &[&str] = &[
6
+ "AggregateError",
7
+ "Array",
8
+ "ArrayBuffer",
9
+ "AsyncFunction",
10
+ "AsyncGenerator",
11
+ "AsyncGeneratorFunction",
12
+ "AsyncIterator",
13
+ "Atomics",
14
+ "BigInt",
15
+ "BigInt64Array",
16
+ "BigUint64Array",
17
+ "Boolean",
18
+ "DataView",
19
+ "Date",
20
+ "decodeURI",
21
+ "decodeURIComponent",
22
+ "encodeURI",
23
+ "encodeURIComponent",
24
+ "Error",
25
+ "escape",
26
+ "eval",
27
+ "EvalError",
28
+ "FinalizationRegistry",
29
+ "Float32Array",
30
+ "Float64Array",
31
+ "Function",
32
+ "Generator",
33
+ "GeneratorFunction",
34
+ "globalThis",
35
+ "Infinity",
36
+ "Int16Array",
37
+ "Int32Array",
38
+ "Int8Array",
39
+ // "InternalError", // non-standard
40
+ "Intl",
41
+ "isFinite",
42
+ "isNaN",
43
+ "Iterator",
44
+ "JSON",
45
+ "Map",
46
+ "Math",
47
+ "NaN",
48
+ "Number",
49
+ "Object",
50
+ "parseFloat",
51
+ "parseInt",
52
+ "Promise",
53
+ "Proxy",
54
+ "RangeError",
55
+ "ReferenceError",
56
+ "Reflect",
57
+ "RegExp",
58
+ "Set",
59
+ "SharedArrayBuffer",
60
+ "String",
61
+ "Symbol",
62
+ "SyntaxError",
63
+ "TypeError",
64
+ "Uint16Array",
65
+ "Uint32Array",
66
+ "Uint8Array",
67
+ "Uint8ClampedArray",
68
+ "undefined",
69
+ "unescape",
70
+ "URIError",
71
+ "WeakMap",
72
+ "WeakRef",
73
+ "WeakSet",
74
+];
75
+
76
#[napi]
4
-pub fn add(left: i32, right: i32) -> i32 {
5
- left + right
77
+pub fn parse(source: String, options: ParseOptions) -> ParseResult {
78
+ let program = match forget_hermes_parser::parse(&source, &options.file) {
79
+ Ok(program) => program,
80
+ Err(diagnostics) => {
81
+ return ParseResult {
82
+ program: None,
83
+ diagnostics: convert_diagnostics(diagnostics),
84
+ };
85
+ }
86
+ };
87
+ let mut analysis = analyze(
88
+ &program,
89
+ AnalyzeOptions {
90
+ globals: GLOBALS.iter().map(|s| s.to_string()).collect(),
91
+ },
92
+ );
93
+ ParseResult {
94
+ program: Some(serde_json::to_string(&program).unwrap()),
95
+ diagnostics: convert_diagnostics(analysis.diagnostics()),
96
+ }
97
+}
98
+
99
+fn convert_diagnostics(diagnostics: Vec<Diagnostic>) -> Vec<String> {
100
+ diagnostics
101
+ .into_iter()
102
+ .map(|diagnostic| format!("{}", diagnostic))
103
+ .collect()
104
}
105
8
-#[cfg(test)]
9
-mod tests {
10
- use super::*;
106
+#[napi(object)]
107
+pub struct ParseOptions {
108
+ pub file: String,
109
+}
110
12
- #[test]
13
- fn it_works() {
14
- let result = add(2, 2);
15
- assert_eq!(result, 4);
16
- }
111
+#[napi(object)]
112
+pub struct ParseResult {
113
+ pub program: Option<String>,
114
+ pub diagnostics: Vec<String>,
115
}