use crate::error::SyntaxError;
use crate::error::SyntaxErrorType;
use crate::loc::Loc;
use crate::num::JsNumber;
use crate::operator::OperatorName;
use ahash::AHashMap;
use core::fmt::Debug;
use serde::Serialize;
use serde::Serializer;
use std::any::Any;
use std::any::TypeId;
use std::fmt;
use std::fmt::Formatter;
#[derive(Default)]
pub struct NodeAssocData {
map: AHashMap<TypeId, Box<dyn Any>>,
}
impl NodeAssocData {
pub fn get<T: Any>(&self) -> Option<&T> {
let t = TypeId::of::<T>();
self.map.get(&t).map(|v| v.downcast_ref().unwrap())
}
pub fn set<T: Any>(&mut self, v: T) {
let t = TypeId::of::<T>();
self.map.insert(t, Box::from(v));
}
}
#[cfg(test)]
mod tests {
use crate::ast::NodeAssocData;
#[test]
fn test_node_assoc_data() {
struct MyType(u32);
let mut assoc = NodeAssocData::default();
assoc.set(MyType(32));
let v = assoc.get::<MyType>().unwrap();
assert_eq!(v.0, 32);
}
}
pub struct Node {
pub loc: Loc,
pub stx: Box<Syntax>,
pub assoc: NodeAssocData,
}
impl Node {
pub fn new(loc: Loc, stx: Syntax) -> Node {
Node {
loc,
stx: Box::new(stx),
assoc: NodeAssocData::default(),
}
}
pub fn error(&self, typ: SyntaxErrorType) -> SyntaxError {
self.loc.error(typ, None)
}
pub fn as_ident(&self) -> &str {
match self.stx.as_ref() {
Syntax::IdentifierExpr { name } => name.as_str(),
_ => unreachable!(),
}
}
}
impl Debug for Node {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.stx.fmt(f)
}
}
impl Serialize for Node {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.stx.serialize(serializer)
}
}
type Declaration = Node;
type Expression = Node;
type Pattern = Node;
type Statement = Node;
#[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize)]
pub enum VarDeclMode {
Const,
Let,
Var,
}
#[derive(Debug, Serialize)]
pub enum ArrayElement {
Single(Expression),
Rest(Expression),
Empty,
}
#[derive(Debug, Serialize)]
pub enum ClassOrObjectMemberKey {
Direct(String),
Computed(Expression),
}
#[derive(Debug, Serialize)]
pub enum ClassOrObjectMemberValue {
Getter {
function: Node, },
Method {
function: Node, },
Property {
initializer: Option<Expression>,
},
Setter {
function: Node, },
}
#[derive(Debug, Serialize)]
pub enum ObjectMemberType {
Valued {
key: ClassOrObjectMemberKey,
value: ClassOrObjectMemberValue,
},
Shorthand {
identifier: Node, },
Rest {
value: Expression,
},
}
#[derive(Debug, Serialize)]
pub struct ArrayPatternElement {
pub target: Pattern,
pub default_value: Option<Expression>,
}
#[derive(Debug, Serialize)]
pub struct ExportName {
pub target: String,
pub alias: Pattern,
}
#[derive(Debug, Serialize)]
pub enum ExportNames {
All(Option<Pattern>),
Specific(Vec<ExportName>),
}
#[derive(Debug, Serialize)]
pub struct VariableDeclarator {
pub pattern: Pattern,
pub initializer: Option<Expression>,
}
#[derive(Debug, Serialize)]
pub enum ForInit {
None,
Expression(Expression),
Declaration(Declaration),
}
#[derive(Debug, Serialize)]
pub enum LiteralTemplatePart {
Substitution(Expression),
String(String),
}
#[derive(Debug, Serialize)]
#[serde(tag = "$t")]
pub enum Syntax {
IdentifierPattern {
name: String,
},
ArrayPattern {
elements: Vec<Option<ArrayPatternElement>>,
rest: Option<Pattern>,
},
ObjectPattern {
properties: Vec<Node>,
rest: Option<Pattern>,
},
ClassOrFunctionName {
name: String,
},
Function {
arrow: bool,
async_: bool,
generator: bool,
parameters: Vec<Declaration>, body: Node, },
FunctionBody {
body: Vec<Statement>,
},
ClassDecl {
export: bool,
export_default: bool,
name: Option<Node>, extends: Option<Expression>,
members: Vec<Node>, },
FunctionDecl {
export: bool,
export_default: bool,
name: Option<Node>, function: Node, },
ParamDecl {
rest: bool,
pattern: Pattern,
default_value: Option<Expression>,
},
VarDecl {
export: bool,
mode: VarDeclMode,
declarators: Vec<VariableDeclarator>,
},
ArrowFunctionExpr {
parenthesised: bool,
function: Node, },
BinaryExpr {
parenthesised: bool,
operator: OperatorName,
left: Expression,
right: Expression,
},
CallExpr {
optional_chaining: bool,
parenthesised: bool,
callee: Expression,
arguments: Vec<Node>,
},
ClassExpr {
parenthesised: bool,
name: Option<Node>,
extends: Option<Expression>,
members: Vec<Node>, },
ConditionalExpr {
parenthesised: bool,
test: Expression,
consequent: Expression,
alternate: Expression,
},
ComputedMemberExpr {
optional_chaining: bool,
object: Expression,
member: Expression,
},
FunctionExpr {
parenthesised: bool,
name: Option<Node>,
function: Node,
},
IdentifierExpr {
name: String,
},
ImportExpr {
module: Expression,
},
ImportMeta {},
JsxAttribute {
name: Expression, value: Option<Expression>, },
JsxElement {
name: Option<Expression>, attributes: Vec<Expression>, children: Vec<Expression>, },
JsxExpressionContainer {
value: Expression,
},
JsxMemberExpression {
base: Node, path: Vec<String>,
},
JsxName {
namespace: Option<String>,
name: String,
},
JsxSpreadAttribute {
value: Expression,
},
JsxText {
value: String,
},
LiteralArrayExpr {
elements: Vec<ArrayElement>,
},
LiteralBigIntExpr {
value: String,
},
LiteralBooleanExpr {
value: bool,
},
LiteralNull {},
LiteralNumberExpr {
value: JsNumber,
},
LiteralObjectExpr {
members: Vec<Node>,
},
LiteralRegexExpr {
value: String, },
LiteralStringExpr {
value: String,
},
LiteralTemplateExpr {
parts: Vec<LiteralTemplatePart>,
},
MemberExpr {
parenthesised: bool,
optional_chaining: bool,
left: Expression,
right: String,
},
SuperExpr {},
ThisExpr {},
TaggedTemplateExpr {
function: Expression,
parts: Vec<LiteralTemplatePart>,
},
UnaryExpr {
parenthesised: bool,
operator: OperatorName,
argument: Expression,
},
UnaryPostfixExpr {
parenthesised: bool,
operator: OperatorName,
argument: Expression,
},
BlockStmt {
body: Vec<Statement>,
},
BreakStmt {
label: Option<String>,
},
ContinueStmt {
label: Option<String>,
},
DebuggerStmt {},
DoWhileStmt {
condition: Expression,
body: Statement,
},
EmptyStmt {},
ExportDefaultExprStmt {
expression: Expression,
},
ExportListStmt {
names: ExportNames,
from: Option<String>,
},
ExpressionStmt {
expression: Expression,
},
IfStmt {
test: Expression,
consequent: Statement,
alternate: Option<Statement>,
},
ImportStmt {
default: Option<Pattern>,
names: Option<ExportNames>,
module: String,
},
ForStmt {
init: ForInit,
condition: Option<Expression>,
post: Option<Expression>,
body: Statement, },
ForInStmt {
decl_mode: Option<VarDeclMode>,
pat: Pattern,
rhs: Expression,
body: Statement, },
ForOfStmt {
await_: bool,
decl_mode: Option<VarDeclMode>,
pat: Pattern,
rhs: Expression,
body: Statement, },
LabelStmt {
name: String,
statement: Statement,
},
ReturnStmt {
value: Option<Expression>,
},
SwitchStmt {
test: Expression,
branches: Vec<Node>,
},
ThrowStmt {
value: Expression,
},
TryStmt {
wrapped: Statement,
catch: Option<Node>,
finally: Option<Statement>,
},
WhileStmt {
condition: Expression,
body: Statement,
},
TopLevel {
body: Vec<Statement>,
},
CallArg {
spread: bool,
value: Expression,
},
CatchBlock {
parameter: Option<Pattern>,
body: Vec<Statement>, },
ClassMember {
key: ClassOrObjectMemberKey,
static_: bool,
value: ClassOrObjectMemberValue,
},
ForBody {
body: Vec<Statement>,
},
ObjectMember {
typ: ObjectMemberType,
},
ObjectPatternProperty {
key: ClassOrObjectMemberKey,
target: Pattern,
shorthand: bool,
default_value: Option<Expression>,
},
SwitchBranch {
case: Option<Expression>,
body: Vec<Statement>,
},
}