[rust] estree codegen for improved serialization

This is meant to replace the initial `estree` crate with a version that is 
generated from a JSON description of ESTree. The idea is to make it easy to 
experiment with slightly different representations to balance ergonomic usage of 
the data at runtime with serialization compatible with ESTree spec. The JSON 
schema looks like this (somewhat abbreviated): 

``` 

{ 

// Objects are struct types that don't have a `type` and can't appear as an enum 
variant 

objects: { 

Position: { 

line: {type: "NonZeroU32"}, 

column: {type: "u32"} 

}, 

... 

}, 

// Nodes are struct types with a `type` and which can appear as enum variants 
(statements, expressions, patterns, etc) 

nodes: { 

ArrayExpression: { 

elements: { 

type: "Expression", 

plural: true, 

nullable_item: true, 

} 

} 

... 

}, 

// Categories of nodes with multiple variants, represented as enums. 

// Can be recursive, eg ForInit can be VariableDeclaration or Expression, 

// where Expression is also an enum 

enums: { 

Expression: [ 

"ArrayExpression", 

... 

] 

}, 

// Simple enums which have a corresponding string value. Used primarily for 
operators (binary/unary/logical/etc) 

// but also for things like variable declaration kind (var/const/let) 

operators: { 

BinaryOperator: { 

Plus: "+", 

Instanceof: "instanceof", 

} 

} 

} 

``` 

The core estree files are now generated using Cargo's build script mechanism. 
Right now i only defined the types and fields from ES5, so i'll have to flush 
out the rest of the modern JS spec and extensions like JSX, TypeScript, and 
Flow. But already the for-statement example works, showing that this approach 
can handle complex cases such as unions of types or other unions (ForStatement 
initializer is tricky bc it can be a VariableDeclaration or an Expression - that 
works now!). 

This is still WIP a bit - now that the ESTree definition is more precise i can 
go back and clean up some other code (have to, because the swc -> estree 
conversion needs some tweaks now).
This commit is contained in:
Joe Savona
2023-07-08 22:59:56 +09:00
parent a32a2baa73
commit 0c1193ecd7
20 changed files with 3497 additions and 6587 deletions
+28 -4
View File
@@ -461,12 +461,25 @@ version = "0.1.0"
dependencies = [
"bumpalo",
"elsa",
"estree-codegen",
"insta",
"serde",
"serde_json",
"static_assertions",
]
[[package]]
name = "estree-codegen"
version = "0.1.0"
dependencies = [
"indexmap 2.0.0",
"prettyplease",
"quote",
"serde",
"serde_json",
"syn 2.0.23",
]
[[package]]
name = "estree-swc"
version = "0.1.0"
@@ -683,6 +696,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [
"equivalent",
"hashbrown 0.14.0",
"serde",
]
[[package]]
@@ -1219,6 +1233,16 @@ dependencies = [
"tracing",
]
[[package]]
name = "prettyplease"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387"
dependencies = [
"proc-macro2",
"syn 2.0.23",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1460,9 +1484,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.166"
version = "1.0.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8"
checksum = "7daf513456463b42aa1d94cff7e0c24d682b429f020b9afa4f5ba5c40a22b237"
dependencies = [
"serde_derive",
]
@@ -1480,9 +1504,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.166"
version = "1.0.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6"
checksum = "b69b106b68bc8054f0e974e70d19984040f8a5cf9215ca82626ea4853f82c4b9"
dependencies = [
"proc-macro2",
"quote",
+1
View File
@@ -6,6 +6,7 @@ members = [
"crates/hir",
"crates/swc-demo",
"crates/estree",
"crates/estree-codegen",
"crates/estree-swc",
]
@@ -0,0 +1,14 @@
[package]
name = "estree-codegen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
indexmap = { version = "2.0.0", features = ["serde"] }
prettyplease = "0.2.10"
quote = "1.0.29"
serde = { version = "1.0.167", features = ["serde_derive"] }
serde_json = "1.0.100"
syn = "2.0.23"
@@ -0,0 +1,416 @@
use std::collections::HashSet;
use indexmap::IndexMap;
use quote::{__private::TokenStream, format_ident, quote};
use serde::{Deserialize, Serialize};
/// Returns prettyplease-formatted Rust source for estree
pub fn estree() -> String {
let src = include_str!("./ecmascript.json");
let grammar: Grammar = serde_json::from_str(src).unwrap();
let raw = grammar.codegen().to_string();
let parsed = syn::parse_file(&raw).unwrap();
prettyplease::unparse(&parsed)
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Grammar {
pub objects: IndexMap<String, Object>,
pub nodes: IndexMap<String, Node>,
pub enums: IndexMap<String, Enum>,
pub operators: IndexMap<String, Operator>,
}
impl Grammar {
pub fn codegen(self) -> TokenStream {
let Self {
objects,
nodes,
enums,
operators,
} = self;
let nodelike: HashSet<String> =
// nodes.keys().cloned().chain(enums.keys().cloned()).collect();
Default::default();
let enum_names: HashSet<String> = enums.keys().cloned().collect();
let mut node_names: Vec<_> = nodes.keys().cloned().collect();
node_names.sort();
let node_variants: Vec<_> = node_names
.iter()
.map(|name| {
let name = format_ident!("{}", name);
quote!(#name(Box<#name>))
})
.collect();
let objects: Vec<_> = objects
.iter()
.map(|(name, object)| object.codegen(name, &nodelike))
.collect();
let nodes: Vec<_> = nodes
.iter()
.map(|(name, node)| node.codegen(name, &nodelike))
.collect();
let enums: Vec<_> = enums
.iter()
.map(|(name, enum_)| enum_.codegen(name, &enum_names))
.collect();
let operators: Vec<_> = operators
.iter()
.map(|(name, operator)| operator.codegen(name))
.collect();
quote! {
use std::num::NonZeroU32;
use serde::{Serialize, Deserialize};
use crate::{JsValue, Binding, SourceRange};
#(#objects)*
#(#nodes)*
#(#enums)*
#(#operators)*
// #[derive(Serialize, Deserialize, Clone, Debug)]
// #[serde(tag = "type")]
// pub enum Node {
// #(#node_variants),*
// }
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Object {
#[serde(default)]
pub fields: IndexMap<String, Field>,
}
impl Object {
pub fn codegen(&self, name: &str, nodes: &HashSet<String>) -> TokenStream {
let name = format_ident!("{}", name);
let fields: Vec<_> = self
.fields
.iter()
.map(|(name, field)| field.codegen(name, nodes))
.collect();
quote! {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct #name {
#(#fields),*
}
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Node {
#[serde(default)]
pub fields: IndexMap<String, Field>,
}
impl Node {
pub fn codegen(&self, name: &str, nodes: &HashSet<String>) -> TokenStream {
let name = format_ident!("{}", name);
let fields: Vec<_> = self
.fields
.iter()
.map(|(name, field)| field.codegen_node(name, nodes))
.collect();
quote! {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct #name {
#(#fields,)*
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
// impl #name {
// pub fn from_node(node: Node) -> Option<Box<Self>> {
// match node {
// Node::#name(node) => Some(node),
// _ => None
// }
// }
// }
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Field {
#[serde(rename = "type")]
pub type_: String,
#[serde(default)]
pub nullable: bool,
#[serde(default)]
pub optional: bool,
#[serde(default)]
pub plural: bool,
#[serde(default)]
pub nullable_item: bool,
#[serde(default)]
pub flatten: bool,
}
impl Field {
pub fn codegen(&self, name: &str, nodes: &HashSet<String>) -> TokenStream {
let name = format_ident!("{}", name);
let type_name = format_ident!(
"{}",
if nodes.contains(&self.type_) {
"Node"
} else {
&self.type_
}
);
let mut type_ = quote!(#type_name);
if self.plural {
if self.nullable_item {
type_ = quote!(Option<#type_>);
}
type_ = quote! { Vec<#type_> };
} else {
assert_eq!(
self.nullable_item, false,
"Can only set nullable_item if plural"
)
}
if self.nullable || self.optional {
assert_eq!(
self.optional, false,
"Expected field to be nullable if optional"
);
type_ = quote!(Option<#type_>);
}
let mut field = quote!(#name: #type_);
if self.optional {
field = quote! {
#[serde(default)]
#field
}
}
if self.flatten {
field = quote! {
#[serde(flatten)]
#field
}
}
field
}
pub fn codegen_node(&self, name: &str, nodes: &HashSet<String>) -> TokenStream {
let name = format_ident!("{}", name);
let type_name = format_ident!(
"{}",
if nodes.contains(&self.type_) {
"Node"
} else {
&self.type_
}
);
let mut type_ = quote!(#type_name);
if self.plural {
if self.nullable_item {
type_ = quote!(Option<#type_>);
}
type_ = quote! { Vec<#type_> };
} else {
assert_eq!(
self.nullable_item, false,
"Can only set nullable_item if plural"
)
}
if self.nullable || self.optional {
assert_eq!(
self.nullable, true,
"Expected field to be nullable if optional"
);
type_ = quote!(Option<#type_>);
}
let mut field = quote!(#name: #type_);
if self.optional {
field = quote! {
#[serde(default)]
#field
}
}
if self.flatten {
field = quote! {
#[serde(flatten)]
#field
}
}
if nodes.contains(&self.type_) {
let comment = format!(" {}", &self.type_);
field = quote! {
#[doc = #comment]
#field
}
}
field
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(transparent)]
pub struct Enum {
pub variants: Vec<String>,
}
impl Enum {
pub fn codegen(&self, name: &str, enums: &HashSet<String>) -> TokenStream {
let mut sorted_variants: Vec<_> = self.variants.iter().collect();
sorted_variants.sort();
let name = format_ident!("{}", name);
let variants: Vec<_> = sorted_variants
.iter()
.map(|name| {
let variant = format_ident!("{}", name);
if enums.contains(*name) {
quote!(#variant(#variant))
} else {
quote!(#variant(Box<#variant>))
}
})
.collect();
let from_node_matches: Vec<_> = sorted_variants
.iter()
.map(|name| {
let variant = format_ident!("{}", name);
if enums.contains(*name) {
quote! {
if let Some(node) = #variant::from_node(node) {
return Some(Self::#variant(node));
}
}
} else {
quote! {
if let Some(node) = #variant::from_node(node) {
return Some(Self::#variant(node));
}
}
}
})
.collect();
let enum_ = quote! {
pub enum #name {
#(#variants),*
}
};
let enum_ = if sorted_variants.iter().any(|name| enums.contains(*name)) {
// contains recursive enum, use untagged serialization
quote! {
#[serde(untagged)]
#enum_
}
} else {
quote! {
#[serde(tag = "type")]
#enum_
}
};
quote! {
#[derive(Serialize, Deserialize, Clone, Debug)]
#enum_
// impl #name {
// pub fn from_node(node: Node) -> Option<Self> {
// #(#from_node_matches)*
// None
// }
// }
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(transparent)]
pub struct Operator {
pub variants: IndexMap<String, String>,
}
impl Operator {
pub fn codegen(&self, name: &str) -> TokenStream {
let mut sorted_variants: Vec<_> = self.variants.iter().collect();
sorted_variants.sort();
let name = format_ident!("{}", name);
let variants: Vec<_> = sorted_variants
.iter()
.map(|(name, operator)| {
let name = format_ident!("{}", name);
let comment = format!(" {}", &operator);
quote! {
#[doc = #comment]
#[serde(rename = #operator)]
#name
}
})
.collect();
let display_matches: Vec<_> = sorted_variants
.iter()
.map(|(name, operator)| {
let name = format_ident!("{}", name);
quote!(Self::#name => #operator)
})
.collect();
let fromstr_matches: Vec<_> = sorted_variants
.iter()
.map(|(name, operator)| {
let name = format_ident!("{}", name);
quote!(#operator => Ok(Self::#name))
})
.collect();
quote! {
#[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum #name {
#(#variants),*
}
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
#(#display_matches),*
};
f.write_str(name)
}
}
impl std::str::FromStr for #name {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#(#fromstr_matches,)*
_ => Err(()),
}
}
}
}
}
}
@@ -0,0 +1,596 @@
{
"objects": {
"SourceLocation": {
"fields": {
"source": {
"type": "String",
"nullable": true
},
"start": {
"type": "Position"
},
"end": {
"type": "Position"
}
}
},
"Position": {
"fields": {
"line": {
"type": "NonZeroU32"
},
"column": {
"type": "u32"
}
}
},
"Function": {
"fields": {
"id": {
"type": "Identifier",
"nullable": true
},
"params": {
"type": "Pattern",
"plural": true
},
"body": {
"type": "BlockStatement",
"nullable": true
}
}
},
"RegExpValue": {
"fields": {
"pattern": {
"type": "String"
},
"flags": {
"type": "String"
}
}
}
},
"nodes": {
"Identifier": {
"fields": {
"name": {
"type": "String"
},
"binding": {
"type": "Binding",
"nullable": true,
"optional": true,
"skip": true
}
}
},
"Literal": {
"fields": {
"value": {
"type": "JsValue"
},
"raw": {
"type": "String",
"nullable": true,
"optional": true
},
"regex": {
"type": "RegExpValue",
"nullable": true,
"optional": true
}
}
},
"Program": {
"fields": {
"body": {
"type": "Statement",
"plural": true
}
}
},
"ExpressionStatement": {
"fields": {
"expression": {
"type": "Expression"
}
}
},
"BlockStatement": {
"fields": {
"body": {
"type": "Statement",
"plural": true
}
}
},
"EmptyStatement": {},
"DebuggerStatement": {},
"WithStatement": {
"fields": {
"object": {
"type": "Expression"
},
"body": {
"type": "Statement"
}
}
},
"ReturnStatement": {
"fields": {
"argument": {
"type": "Expression",
"nullable": true
}
}
},
"LabeledStatement": {
"fields": {
"label": {
"type": "Identifier"
},
"body": {
"type": "Statement"
}
}
},
"BreakStatement": {
"fields": {
"label": {
"type": "Identifier",
"nullable": true
}
}
},
"ContinueStatement": {
"fields": {
"label": {
"type": "Identifier",
"nullable": true
}
}
},
"IfStatement": {
"fields": {
"test": {
"type": "Expression"
},
"consequent": {
"type": "Statement"
},
"alternate": {
"type": "Statement",
"nullable": true
}
}
},
"SwitchStatement": {
"fields": {
"discriminant": {
"type": "Expression"
},
"cases": {
"type": "SwitchCase",
"plural": true
}
}
},
"SwitchCase": {
"fields": {
"test": {
"type": "Expression",
"nullable": true
},
"consequent": {
"type": "Statement",
"plural": true
}
}
},
"ThrowStatement": {
"fields": {
"argument": {
"type": "Expression"
}
}
},
"TryStatement": {
"fields": {
"block": {
"type": "BlockStatement"
},
"handler": {
"type": "CatchClause",
"nullable": true
},
"finalizer": {
"type": "BlockStatement",
"nullable": true
}
}
},
"CatchClause": {
"fields": {
"param": {
"type": "Pattern"
},
"body": {
"type": "BlockStatement"
}
}
},
"WhileStatement": {
"fields": {
"test": {
"type": "Expression"
},
"body": {
"type": "Statement"
}
}
},
"DoWhileStatement": {
"fields": {
"body": {
"type": "Statement"
},
"test": {
"type": "Expression"
}
}
},
"ForStatement": {
"fields": {
"init": {
"type": "ForInit",
"nullable": true
},
"test": {
"type": "Expression",
"nullable": true
},
"update": {
"type": "Expression",
"nullable": true
},
"body": {
"type": "Statement"
}
}
},
"ForInStatement": {
"fields": {
"left": {
"type": "ForInInit"
},
"right": {
"type": "Expression"
},
"body": {
"type": "Statement"
}
}
},
"FunctionDeclaration": {
"fields": {
"function": {
"type": "Function",
"flatten": true
}
}
},
"VariableDeclaration": {
"fields": {
"kind": {
"type": "VariableDeclarationKind"
},
"declarations": {
"type": "VariableDeclarator",
"plural": true
}
}
},
"VariableDeclarator": {
"fields": {
"id": {
"type": "Pattern"
},
"init": {
"type": "Expression",
"nullable": true
}
}
},
"ThisExpression": {},
"ArrayExpression": {
"fields": {
"elements": {
"type": "Expression",
"plural": true,
"nullable_item": true
}
}
},
"ObjectExpression": {
"fields": {
"properties": {
"type": "Property",
"plural": true
}
}
},
"Property": {
"fields": {
"key": {
"type": "PropertyKey"
},
"value": {
"type": "Expression"
},
"kind": {
"type": "PropertyKind"
}
}
},
"FunctionExpression": {
"fields": {
"function": {
"type": "Function",
"flatten": true
}
}
},
"UnaryExpression": {
"fields": {
"operator": {
"type": "UnaryOperator"
},
"prefix": {
"type": "bool"
},
"argument": {
"type": "Expression"
}
}
},
"UpdateExpression": {
"fields": {
"operator": {
"type": "UpdateOperator"
},
"argument": {
"type": "Expression"
},
"prefix": {
"type": "bool"
}
}
},
"BinaryExpression": {
"fields": {
"left": {
"type": "Expression"
},
"operator": {
"type": "BinaryOperator"
},
"right": {
"type": "Expression"
}
}
},
"AssignmentExpression": {
"fields": {
"operator": {
"type": "AssignmentOperator"
},
"left": {
"type": "AssignmentTarget"
},
"right": {
"type": "Expression"
}
}
},
"LogicalExpression": {
"fields": {
"operator": {
"type": "LogicalOperator"
},
"left": {
"type": "Expression"
},
"right": {
"type": "Expression"
}
}
},
"MemberExpression": {
"fields": {
"object": {
"type": "Expression"
},
"property": {
"type": "Expression"
},
"computed": {
"type": "bool"
}
}
},
"ConditionalExpression": {
"fields": {
"test": {
"type": "Expression"
},
"alternate": {
"type": "Expression"
},
"consequent": {
"type": "Expression"
}
}
},
"CallExpression": {
"type": true,
"fields": {
"callee": {
"type": "Expression"
},
"arguments": {
"type": "Expression",
"plural": true
}
}
},
"NewExpression": {
"type": true,
"fields": {
"callee": {
"type": "Expression"
},
"arguments": {
"type": "Expression",
"plural": true
}
}
},
"SequenceExpression": {
"type": true,
"fields": {
"expressions": {
"type": "Expression",
"plural": true
}
}
}
},
"enums": {
"Statement": [
"BlockStatement",
"BreakStatement",
"ContinueStatement",
"DebuggerStatement",
"DoWhileStatement",
"EmptyStatement",
"ExpressionStatement",
"ForInStatement",
"ForStatement",
"FunctionDeclaration",
"IfStatement",
"LabeledStatement",
"ReturnStatement",
"SwitchStatement",
"ThrowStatement",
"TryStatement",
"VariableDeclaration",
"WhileStatement",
"WithStatement"
],
"Expression": [
"ArrayExpression",
"AssignmentExpression",
"BinaryExpression",
"CallExpression",
"ConditionalExpression",
"FunctionExpression",
"Identifier",
"Literal",
"LogicalExpression",
"MemberExpression",
"NewExpression",
"ObjectExpression",
"SequenceExpression",
"ThisExpression",
"UnaryExpression",
"UpdateExpression"
],
"Pattern": [
"Identifier"
],
"ForInit": [
"Expression",
"VariableDeclaration"
],
"ForInInit": [
"Pattern",
"VariableDeclaration"
],
"PropertyKey": [
"Identifier",
"Literal"
],
"AssignmentTarget": [
"Expression",
"Pattern"
]
},
"operators": {
"VariableDeclarationKind": {
"Const": "const",
"Let": "let",
"Var": "var"
},
"PropertyKind": {
"Get": "get",
"Init": "init",
"Set": "set"
},
"UnaryOperator": {
"Delete": "delete",
"Minus": "-",
"Negation": "!",
"Plus": "+",
"Tilde": "~",
"Typeof": "typeof",
"Void": "void"
},
"UpdateOperator": {
"Decrement": "--",
"Increment": "++"
},
"BinaryOperator": {
"Add": "+",
"BinaryAnd": "&",
"BinaryOr": "|",
"BinaryXor": "^",
"Divide": "/",
"Equals": "==",
"GreaterThan": ">",
"GreaterThanOrEqual": ">=",
"In": "in",
"Instanceof": "instanceof",
"LessThan": "<",
"LessThanOrEqual": "<=",
"Modulo": "%",
"Multiply": "*",
"NotEquals": "!=",
"NotStrictEquals": "!==",
"ShiftLeft": "<<",
"ShiftRight": ">>",
"StrictEquals": "===",
"Subtract": "-",
"UnsignedShiftRight": ">>>"
},
"AssignmentOperator": {
"BinaryAndEquals": "&=",
"BinaryOrEquals": "|=",
"BinaryXorEquals": "^=",
"DivideEquals": "/=",
"Equals": "=",
"MinusEquals": "-=",
"ModuloEquals": "%=",
"MultiplyEquals": "*=",
"PlusEquals": "+=",
"ShiftLeftEquals": "<<=",
"ShiftRightEquals": ">>=",
"UnsignedShiftRightEquals": ">>>="
},
"LogicalOperator": {
"And": "&&",
"NullCoalescing": "??",
"Or": "||"
}
}
}
@@ -0,0 +1,3 @@
mod codegen;
pub use codegen::estree;
+3
View File
@@ -12,3 +12,6 @@ insta = { version = "1.30.0", features = ["glob"] }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.99"
static_assertions = "1.1.0"
[build-dependencies]
estree-codegen = { path = "../estree-codegen" }
+13
View File
@@ -0,0 +1,13 @@
use estree_codegen::estree;
// Example custom build script.
fn main() {
// Re-run if the codegen files change
println!("cargo:rerun-if-changed=../estree-codegen/src/codegen.rs");
println!("cargo:rerun-if-changed=../estree-codegen/src/lib.rs");
println!("cargo:rerun-if-changed=../estree-codegen/src/ecmascript.json");
println!("cargo:rerun-if-changed=../estree-codegen");
let src = estree();
std::fs::write("src/generated.rs", src).unwrap();
}
@@ -0,0 +1,4 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Binding;
@@ -1,528 +0,0 @@
{
"type": "Program",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 7,
"column": 1
}
},
"body": [
{
"type": "FunctionDeclaration",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 7,
"column": 1
}
},
"id": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 18
}
},
"name": "Component",
"typeAnnotation": null,
"optional": false,
"range": [
9,
18
]
},
"params": [
{
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 24
}
},
"name": "props",
"typeAnnotation": null,
"optional": false,
"range": [
19,
24
]
}
],
"body": {
"type": "BlockStatement",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 7,
"column": 1
}
},
"body": [
{
"type": "VariableDeclaration",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 12
}
},
"kind": "let",
"declarations": [
{
"type": "VariableDeclarator",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 6
},
"end": {
"line": 2,
"column": 11
}
},
"init": {
"type": "Literal",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 11
}
},
"value": 0,
"range": [
38,
39
],
"raw": "0"
},
"id": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 6
},
"end": {
"line": 2,
"column": 7
}
},
"name": "x",
"typeAnnotation": null,
"optional": false,
"range": [
34,
35
]
},
"range": [
34,
39
]
}
],
"range": [
30,
40
]
},
{
"type": "ForStatement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 5,
"column": 3
}
},
"init": {
"type": "VariableDeclaration",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 16
}
},
"kind": "let",
"declarations": [
{
"type": "VariableDeclarator",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 11
},
"end": {
"line": 3,
"column": 16
}
},
"init": {
"type": "Literal",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 16
}
},
"value": 0,
"range": [
56,
57
],
"raw": "0"
},
"id": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 11
},
"end": {
"line": 3,
"column": 12
}
},
"name": "i",
"typeAnnotation": null,
"optional": false,
"range": [
52,
53
]
},
"range": [
52,
57
]
}
],
"range": [
48,
57
]
},
"test": {
"type": "BinaryExpression",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 24
}
},
"left": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 19
}
},
"name": "i",
"typeAnnotation": null,
"optional": false,
"range": [
59,
60
]
},
"right": {
"type": "Literal",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 22
},
"end": {
"line": 3,
"column": 24
}
},
"value": 10,
"range": [
63,
65
],
"raw": "10"
},
"operator": "<",
"range": [
59,
65
]
},
"update": {
"type": "UpdateExpression",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 26
},
"end": {
"line": 3,
"column": 29
}
},
"operator": "++",
"argument": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 26
},
"end": {
"line": 3,
"column": 27
}
},
"name": "i",
"typeAnnotation": null,
"optional": false,
"range": [
67,
68
]
},
"prefix": false,
"range": [
67,
70
]
},
"body": {
"type": "BlockStatement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 31
},
"end": {
"line": 5,
"column": 3
}
},
"body": [
{
"type": "ExpressionStatement",
"loc": {
"source": null,
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 11
}
},
"expression": {
"type": "AssignmentExpression",
"loc": {
"source": null,
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 10
}
},
"operator": "+=",
"left": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 5
}
},
"name": "x",
"typeAnnotation": null,
"optional": false,
"range": [
78,
79
]
},
"right": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 4,
"column": 9
},
"end": {
"line": 4,
"column": 10
}
},
"name": "i",
"typeAnnotation": null,
"optional": false,
"range": [
83,
84
]
},
"range": [
78,
84
]
},
"directive": null,
"range": [
78,
85
]
}
],
"range": [
72,
89
]
},
"range": [
43,
89
]
},
{
"type": "ReturnStatement",
"loc": {
"source": null,
"start": {
"line": 6,
"column": 2
},
"end": {
"line": 6,
"column": 11
}
},
"argument": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 6,
"column": 9
},
"end": {
"line": 6,
"column": 10
}
},
"name": "x",
"typeAnnotation": null,
"optional": false,
"range": [
99,
100
]
},
"range": [
92,
101
]
}
],
"range": [
26,
103
]
},
"typeParameters": null,
"returnType": null,
"predicate": null,
"generator": false,
"async": false,
"range": [
0,
103
]
}
],
"comments": [],
"interpreter": null,
"range": [
0,
103
],
"sourceType": "script"
}
@@ -0,0 +1,916 @@
use std::num::NonZeroU32;
use serde::{Serialize, Deserialize};
use crate::{JsValue, Binding, SourceRange};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SourceLocation {
source: Option<String>,
start: Position,
end: Position,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Position {
line: NonZeroU32,
column: u32,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Function {
id: Option<Identifier>,
params: Vec<Pattern>,
body: Option<BlockStatement>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RegExpValue {
pattern: String,
flags: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Identifier {
name: String,
#[serde(default)]
binding: Option<Binding>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Literal {
value: JsValue,
#[serde(default)]
raw: Option<String>,
#[serde(default)]
regex: Option<RegExpValue>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Program {
body: Vec<Statement>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExpressionStatement {
expression: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BlockStatement {
body: Vec<Statement>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct EmptyStatement {
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DebuggerStatement {
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct WithStatement {
object: Expression,
body: Statement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ReturnStatement {
argument: Option<Expression>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LabeledStatement {
label: Identifier,
body: Statement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BreakStatement {
label: Option<Identifier>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ContinueStatement {
label: Option<Identifier>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct IfStatement {
test: Expression,
consequent: Statement,
alternate: Option<Statement>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SwitchStatement {
discriminant: Expression,
cases: Vec<SwitchCase>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SwitchCase {
test: Option<Expression>,
consequent: Vec<Statement>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ThrowStatement {
argument: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TryStatement {
block: BlockStatement,
handler: Option<CatchClause>,
finalizer: Option<BlockStatement>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CatchClause {
param: Pattern,
body: BlockStatement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct WhileStatement {
test: Expression,
body: Statement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DoWhileStatement {
body: Statement,
test: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ForStatement {
init: Option<ForInit>,
test: Option<Expression>,
update: Option<Expression>,
body: Statement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ForInStatement {
left: ForInInit,
right: Expression,
body: Statement,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FunctionDeclaration {
#[serde(flatten)]
function: Function,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct VariableDeclaration {
kind: VariableDeclarationKind,
declarations: Vec<VariableDeclarator>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct VariableDeclarator {
id: Pattern,
init: Option<Expression>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ThisExpression {
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ArrayExpression {
elements: Vec<Option<Expression>>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ObjectExpression {
properties: Vec<Property>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Property {
key: PropertyKey,
value: Expression,
kind: PropertyKind,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FunctionExpression {
#[serde(flatten)]
function: Function,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct UnaryExpression {
operator: UnaryOperator,
prefix: bool,
argument: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct UpdateExpression {
operator: UpdateOperator,
argument: Expression,
prefix: bool,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BinaryExpression {
left: Expression,
operator: BinaryOperator,
right: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AssignmentExpression {
operator: AssignmentOperator,
left: AssignmentTarget,
right: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LogicalExpression {
operator: LogicalOperator,
left: Expression,
right: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MemberExpression {
object: Expression,
property: Expression,
computed: bool,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ConditionalExpression {
test: Expression,
alternate: Expression,
consequent: Expression,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CallExpression {
callee: Expression,
arguments: Vec<Expression>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewExpression {
callee: Expression,
arguments: Vec<Expression>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SequenceExpression {
expressions: Vec<Expression>,
#[serde(default)]
pub loc: Option<SourceLocation>,
#[serde(default)]
pub range: Option<SourceRange>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
pub enum Statement {
BlockStatement(Box<BlockStatement>),
BreakStatement(Box<BreakStatement>),
ContinueStatement(Box<ContinueStatement>),
DebuggerStatement(Box<DebuggerStatement>),
DoWhileStatement(Box<DoWhileStatement>),
EmptyStatement(Box<EmptyStatement>),
ExpressionStatement(Box<ExpressionStatement>),
ForInStatement(Box<ForInStatement>),
ForStatement(Box<ForStatement>),
FunctionDeclaration(Box<FunctionDeclaration>),
IfStatement(Box<IfStatement>),
LabeledStatement(Box<LabeledStatement>),
ReturnStatement(Box<ReturnStatement>),
SwitchStatement(Box<SwitchStatement>),
ThrowStatement(Box<ThrowStatement>),
TryStatement(Box<TryStatement>),
VariableDeclaration(Box<VariableDeclaration>),
WhileStatement(Box<WhileStatement>),
WithStatement(Box<WithStatement>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
pub enum Expression {
ArrayExpression(Box<ArrayExpression>),
AssignmentExpression(Box<AssignmentExpression>),
BinaryExpression(Box<BinaryExpression>),
CallExpression(Box<CallExpression>),
ConditionalExpression(Box<ConditionalExpression>),
FunctionExpression(Box<FunctionExpression>),
Identifier(Box<Identifier>),
Literal(Box<Literal>),
LogicalExpression(Box<LogicalExpression>),
MemberExpression(Box<MemberExpression>),
NewExpression(Box<NewExpression>),
ObjectExpression(Box<ObjectExpression>),
SequenceExpression(Box<SequenceExpression>),
ThisExpression(Box<ThisExpression>),
UnaryExpression(Box<UnaryExpression>),
UpdateExpression(Box<UpdateExpression>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
pub enum Pattern {
Identifier(Box<Identifier>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub enum ForInit {
Expression(Expression),
VariableDeclaration(Box<VariableDeclaration>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub enum ForInInit {
Pattern(Pattern),
VariableDeclaration(Box<VariableDeclaration>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
pub enum PropertyKey {
Identifier(Box<Identifier>),
Literal(Box<Literal>),
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
pub enum AssignmentTarget {
Expression(Expression),
Pattern(Pattern),
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum VariableDeclarationKind {
/// const
#[serde(rename = "const")]
Const,
/// let
#[serde(rename = "let")]
Let,
/// var
#[serde(rename = "var")]
Var,
}
impl std::fmt::Display for VariableDeclarationKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Const => "const",
Self::Let => "let",
Self::Var => "var",
};
f.write_str(name)
}
}
impl std::str::FromStr for VariableDeclarationKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"const" => Ok(Self::Const),
"let" => Ok(Self::Let),
"var" => Ok(Self::Var),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum PropertyKind {
/// get
#[serde(rename = "get")]
Get,
/// init
#[serde(rename = "init")]
Init,
/// set
#[serde(rename = "set")]
Set,
}
impl std::fmt::Display for PropertyKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Get => "get",
Self::Init => "init",
Self::Set => "set",
};
f.write_str(name)
}
}
impl std::str::FromStr for PropertyKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"get" => Ok(Self::Get),
"init" => Ok(Self::Init),
"set" => Ok(Self::Set),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum UnaryOperator {
/// delete
#[serde(rename = "delete")]
Delete,
/// -
#[serde(rename = "-")]
Minus,
/// !
#[serde(rename = "!")]
Negation,
/// +
#[serde(rename = "+")]
Plus,
/// ~
#[serde(rename = "~")]
Tilde,
/// typeof
#[serde(rename = "typeof")]
Typeof,
/// void
#[serde(rename = "void")]
Void,
}
impl std::fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Delete => "delete",
Self::Minus => "-",
Self::Negation => "!",
Self::Plus => "+",
Self::Tilde => "~",
Self::Typeof => "typeof",
Self::Void => "void",
};
f.write_str(name)
}
}
impl std::str::FromStr for UnaryOperator {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"delete" => Ok(Self::Delete),
"-" => Ok(Self::Minus),
"!" => Ok(Self::Negation),
"+" => Ok(Self::Plus),
"~" => Ok(Self::Tilde),
"typeof" => Ok(Self::Typeof),
"void" => Ok(Self::Void),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum UpdateOperator {
/// --
#[serde(rename = "--")]
Decrement,
/// ++
#[serde(rename = "++")]
Increment,
}
impl std::fmt::Display for UpdateOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Decrement => "--",
Self::Increment => "++",
};
f.write_str(name)
}
}
impl std::str::FromStr for UpdateOperator {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"--" => Ok(Self::Decrement),
"++" => Ok(Self::Increment),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum BinaryOperator {
/// +
#[serde(rename = "+")]
Add,
/// &
#[serde(rename = "&")]
BinaryAnd,
/// |
#[serde(rename = "|")]
BinaryOr,
/// ^
#[serde(rename = "^")]
BinaryXor,
/// /
#[serde(rename = "/")]
Divide,
/// ==
#[serde(rename = "==")]
Equals,
/// >
#[serde(rename = ">")]
GreaterThan,
/// >=
#[serde(rename = ">=")]
GreaterThanOrEqual,
/// in
#[serde(rename = "in")]
In,
/// instanceof
#[serde(rename = "instanceof")]
Instanceof,
/// <
#[serde(rename = "<")]
LessThan,
/// <=
#[serde(rename = "<=")]
LessThanOrEqual,
/// %
#[serde(rename = "%")]
Modulo,
/// *
#[serde(rename = "*")]
Multiply,
/// !=
#[serde(rename = "!=")]
NotEquals,
/// !==
#[serde(rename = "!==")]
NotStrictEquals,
/// <<
#[serde(rename = "<<")]
ShiftLeft,
/// >>
#[serde(rename = ">>")]
ShiftRight,
/// ===
#[serde(rename = "===")]
StrictEquals,
/// -
#[serde(rename = "-")]
Subtract,
/// >>>
#[serde(rename = ">>>")]
UnsignedShiftRight,
}
impl std::fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Add => "+",
Self::BinaryAnd => "&",
Self::BinaryOr => "|",
Self::BinaryXor => "^",
Self::Divide => "/",
Self::Equals => "==",
Self::GreaterThan => ">",
Self::GreaterThanOrEqual => ">=",
Self::In => "in",
Self::Instanceof => "instanceof",
Self::LessThan => "<",
Self::LessThanOrEqual => "<=",
Self::Modulo => "%",
Self::Multiply => "*",
Self::NotEquals => "!=",
Self::NotStrictEquals => "!==",
Self::ShiftLeft => "<<",
Self::ShiftRight => ">>",
Self::StrictEquals => "===",
Self::Subtract => "-",
Self::UnsignedShiftRight => ">>>",
};
f.write_str(name)
}
}
impl std::str::FromStr for BinaryOperator {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"+" => Ok(Self::Add),
"&" => Ok(Self::BinaryAnd),
"|" => Ok(Self::BinaryOr),
"^" => Ok(Self::BinaryXor),
"/" => Ok(Self::Divide),
"==" => Ok(Self::Equals),
">" => Ok(Self::GreaterThan),
">=" => Ok(Self::GreaterThanOrEqual),
"in" => Ok(Self::In),
"instanceof" => Ok(Self::Instanceof),
"<" => Ok(Self::LessThan),
"<=" => Ok(Self::LessThanOrEqual),
"%" => Ok(Self::Modulo),
"*" => Ok(Self::Multiply),
"!=" => Ok(Self::NotEquals),
"!==" => Ok(Self::NotStrictEquals),
"<<" => Ok(Self::ShiftLeft),
">>" => Ok(Self::ShiftRight),
"===" => Ok(Self::StrictEquals),
"-" => Ok(Self::Subtract),
">>>" => Ok(Self::UnsignedShiftRight),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum AssignmentOperator {
/// &=
#[serde(rename = "&=")]
BinaryAndEquals,
/// |=
#[serde(rename = "|=")]
BinaryOrEquals,
/// ^=
#[serde(rename = "^=")]
BinaryXorEquals,
/// /=
#[serde(rename = "/=")]
DivideEquals,
/// =
#[serde(rename = "=")]
Equals,
/// -=
#[serde(rename = "-=")]
MinusEquals,
/// %=
#[serde(rename = "%=")]
ModuloEquals,
/// *=
#[serde(rename = "*=")]
MultiplyEquals,
/// +=
#[serde(rename = "+=")]
PlusEquals,
/// <<=
#[serde(rename = "<<=")]
ShiftLeftEquals,
/// >>=
#[serde(rename = ">>=")]
ShiftRightEquals,
/// >>>=
#[serde(rename = ">>>=")]
UnsignedShiftRightEquals,
}
impl std::fmt::Display for AssignmentOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::BinaryAndEquals => "&=",
Self::BinaryOrEquals => "|=",
Self::BinaryXorEquals => "^=",
Self::DivideEquals => "/=",
Self::Equals => "=",
Self::MinusEquals => "-=",
Self::ModuloEquals => "%=",
Self::MultiplyEquals => "*=",
Self::PlusEquals => "+=",
Self::ShiftLeftEquals => "<<=",
Self::ShiftRightEquals => ">>=",
Self::UnsignedShiftRightEquals => ">>>=",
};
f.write_str(name)
}
}
impl std::str::FromStr for AssignmentOperator {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"&=" => Ok(Self::BinaryAndEquals),
"|=" => Ok(Self::BinaryOrEquals),
"^=" => Ok(Self::BinaryXorEquals),
"/=" => Ok(Self::DivideEquals),
"=" => Ok(Self::Equals),
"-=" => Ok(Self::MinusEquals),
"%=" => Ok(Self::ModuloEquals),
"*=" => Ok(Self::MultiplyEquals),
"+=" => Ok(Self::PlusEquals),
"<<=" => Ok(Self::ShiftLeftEquals),
">>=" => Ok(Self::ShiftRightEquals),
">>>=" => Ok(Self::UnsignedShiftRightEquals),
_ => Err(()),
}
}
}
#[derive(
Serialize,
Deserialize,
Clone,
Copy,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Debug
)]
pub enum LogicalOperator {
/// &&
#[serde(rename = "&&")]
And,
/// ??
#[serde(rename = "??")]
NullCoalescing,
/// ||
#[serde(rename = "||")]
Or,
}
impl std::fmt::Display for LogicalOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::And => "&&",
Self::NullCoalescing => "??",
Self::Or => "||",
};
f.write_str(name)
}
}
impl std::str::FromStr for LogicalOperator {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"&&" => Ok(Self::And),
"??" => Ok(Self::NullCoalescing),
"||" => Ok(Self::Or),
_ => Err(()),
}
}
}
@@ -1,104 +0,0 @@
{
"type": "Program",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 26
}
},
"body": [
{
"type": "ImportDeclaration",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 26
}
},
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 12
}
},
"local": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 12
}
},
"name": "React",
"typeAnnotation": null,
"optional": false,
"range": [
7,
12
]
},
"range": [
7,
12
]
}
],
"source": {
"type": "Literal",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 25
}
},
"value": "react",
"range": [
18,
25
],
"raw": "'react'"
},
"attributes": [],
"importKind": "value",
"range": [
0,
26
]
}
],
"comments": [],
"interpreter": null,
"range": [
0,
26
],
"sourceType": "module"
}
@@ -0,0 +1,112 @@
use serde::{de::Visitor, Deserialize, Serialize};
#[derive(Serialize, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub enum JsValue {
Undefined,
Null,
Bool(bool),
Number(Number),
String(String),
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
pub struct Number(u64);
impl From<u32> for Number {
fn from(value: u32) -> Self {
Number(value.into())
}
}
impl From<u64> for Number {
fn from(value: u64) -> Self {
Number(value)
}
}
impl From<f64> for Number {
fn from(value: f64) -> Self {
Number(value.to_bits())
}
}
impl From<Number> for f64 {
fn from(value: Number) -> Self {
f64::from_bits(value.0)
}
}
impl<'de> Deserialize<'de> for JsValue {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<JsValue, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = JsValue;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("valid primitive JSON value (null, boolean, number, or string")
}
#[inline]
fn visit_bool<E>(self, value: bool) -> Result<JsValue, E> {
Ok(JsValue::Bool(value))
}
#[inline]
fn visit_i64<E>(self, value: i64) -> Result<JsValue, E> {
if value < u32::MAX as i64 {
Ok(JsValue::Number((value as u32).into()))
} else {
panic!("Invalid number")
}
}
#[inline]
fn visit_u64<E>(self, value: u64) -> Result<JsValue, E> {
Ok(JsValue::Number(value.into()))
}
#[inline]
fn visit_f64<E>(self, value: f64) -> Result<JsValue, E> {
Ok(JsValue::Number(value.into()))
}
#[inline]
fn visit_str<E>(self, value: &str) -> Result<JsValue, E>
where
E: serde::de::Error,
{
self.visit_string(String::from(value))
}
#[inline]
fn visit_string<E>(self, value: String) -> Result<JsValue, E> {
Ok(JsValue::String(value))
}
#[inline]
fn visit_none<E>(self) -> Result<JsValue, E> {
Ok(JsValue::Null)
}
#[inline]
fn visit_some<D>(self, deserializer: D) -> Result<JsValue, D::Error>
where
D: serde::Deserializer<'de>,
{
Deserialize::deserialize(deserializer)
}
#[inline]
fn visit_unit<E>(self) -> Result<JsValue, E> {
Ok(JsValue::Undefined)
}
}
deserializer.deserialize_any(ValueVisitor)
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,9 @@
use std::num::NonZeroU32;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SourceRange {
pub start: u32,
pub end: NonZeroU32,
}
@@ -1,189 +0,0 @@
{
"type": "Program",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"range": [
0,
51
],
"body": [
{
"type": "FunctionDeclaration",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"range": [
0,
51
],
"id": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 18
}
},
"range": [
9,
18
],
"name": "Component",
"typeAnnotation": null,
"optional": false
},
"params": [
{
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 24
}
},
"range": [
19,
24
],
"name": "props",
"typeAnnotation": null,
"optional": false
}
],
"body": {
"type": "BlockStatement",
"loc": {
"source": null,
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 3,
"column": 1
}
},
"range": [
26,
51
],
"body": [
{
"type": "ReturnStatement",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 21
}
},
"range": [
30,
49
],
"argument": {
"type": "MemberExpression",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 20
}
},
"range": [
37,
48
],
"object": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 14
}
},
"range": [
37,
42
],
"name": "props",
"typeAnnotation": null,
"optional": false
},
"property": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 15
},
"end": {
"line": 2,
"column": 20
}
},
"range": [
43,
48
],
"name": "value",
"typeAnnotation": null,
"optional": false
},
"computed": false
}
}
]
},
"async": false,
"generator": false,
"predicate": null,
"expression": false,
"returnType": null,
"typeParameters": null
}
],
"comments": [],
"errors": []
}
@@ -535,7 +535,6 @@ Input:
Output:
{
"sourceType": "script",
"body": [
{
"type": "FunctionDeclaration",
@@ -580,13 +579,11 @@ Output:
}
}
],
"generator": false,
"async": false,
"body": {
"type": "BlockStatement",
"body": [
{
"type": "VariableDeclaration",
"kind": "let",
"declarations": [
{
"id": {
@@ -611,8 +608,11 @@ Output:
},
"init": {
"type": "Literal",
"value": 0,
"value": {
"Number": 0
},
"raw": "0",
"regex": null,
"loc": {
"source": null,
"start": {
@@ -646,7 +646,6 @@ Output:
}
}
],
"kind": "let",
"loc": {
"source": null,
"start": {
@@ -666,7 +665,7 @@ Output:
{
"type": "ForStatement",
"init": {
"type": "VariableDeclaration",
"kind": "let",
"declarations": [
{
"id": {
@@ -691,8 +690,11 @@ Output:
},
"init": {
"type": "Literal",
"value": 0,
"value": {
"Number": 0
},
"raw": "0",
"regex": null,
"loc": {
"source": null,
"start": {
@@ -726,7 +728,6 @@ Output:
}
}
],
"kind": "let",
"loc": {
"source": null,
"start": {
@@ -745,7 +746,6 @@ Output:
},
"test": {
"type": "BinaryExpression",
"operator": "<",
"left": {
"type": "Identifier",
"name": "i",
@@ -766,10 +766,14 @@ Output:
"end": 60
}
},
"operator": "<",
"right": {
"type": "Literal",
"value": 10,
"value": {
"Number": 10
},
"raw": "10",
"regex": null,
"loc": {
"source": null,
"start": {
@@ -906,7 +910,6 @@ Output:
"end": 84
}
},
"directive": null,
"loc": {
"source": null,
"start": {
@@ -1028,7 +1031,6 @@ Output:
}
}
],
"comments": [],
"loc": {
"source": null,
"start": {
-351
View File
@@ -1,351 +0,0 @@
{
"type": "Program",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 4,
"column": 1
}
},
"body": [
{
"type": "FunctionDeclaration",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 4,
"column": 1
}
},
"id": {
"type": "Identifier",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 12
}
},
"name": "foo",
"typeAnnotation": null,
"optional": false,
"range": [
10,
13
]
},
"params": [],
"body": {
"type": "BlockStatement",
"loc": {
"source": null,
"start": {
"line": 2,
"column": 15
},
"end": {
"line": 4,
"column": 1
}
},
"body": [
{
"type": "ReturnStatement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 3,
"column": 36
}
},
"argument": {
"type": "JSXElement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 36
}
},
"openingElement": {
"type": "JSXOpeningElement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 26
}
},
"name": {
"type": "JSXMemberExpression",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 10
},
"end": {
"line": 3,
"column": 17
}
},
"object": {
"type": "JSXIdentifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 10
},
"end": {
"line": 3,
"column": 13
}
},
"name": "Foo",
"range": [
28,
31
]
},
"property": {
"type": "JSXIdentifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 17
}
},
"name": "Bar",
"range": [
32,
35
]
},
"range": [
28,
35
]
},
"attributes": [
{
"type": "JSXAttribute",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 24
}
},
"name": {
"type": "JSXIdentifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 19
}
},
"name": "a",
"range": [
36,
37
]
},
"value": {
"type": "JSXExpressionContainer",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 20
},
"end": {
"line": 3,
"column": 24
}
},
"expression": {
"type": "Literal",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 21
},
"end": {
"line": 3,
"column": 23
}
},
"value": 10,
"range": [
39,
41
],
"raw": "10"
},
"range": [
38,
42
]
},
"range": [
36,
42
]
}
],
"selfClosing": false,
"range": [
27,
44
]
},
"children": [],
"closingElement": {
"type": "JSXClosingElement",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 26
},
"end": {
"line": 3,
"column": 36
}
},
"name": {
"type": "JSXMemberExpression",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 28
},
"end": {
"line": 3,
"column": 35
}
},
"object": {
"type": "JSXIdentifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 28
},
"end": {
"line": 3,
"column": 31
}
},
"name": "Foo",
"range": [
46,
49
]
},
"property": {
"type": "JSXIdentifier",
"loc": {
"source": null,
"start": {
"line": 3,
"column": 32
},
"end": {
"line": 3,
"column": 35
}
},
"name": "Bar",
"range": [
50,
53
]
},
"range": [
46,
53
]
},
"range": [
44,
54
]
},
"range": [
27,
54
]
},
"range": [
20,
54
]
}
],
"range": [
16,
56
]
},
"typeParameters": null,
"returnType": null,
"predicate": null,
"generator": false,
"async": false,
"range": [
1,
56
]
}
],
"comments": [],
"interpreter": null,
"range": [
1,
56
],
"sourceType": "script"
}