use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct Span {
pub start: Position,
pub end: Position,
}
impl Span {
pub fn new(start: u32, end: u32) -> Self {
Self {
start: Position {
offset: start,
line: 1,
column: 0,
},
end: Position {
offset: end,
line: 1,
column: 0,
},
}
}
pub fn unknown() -> Self {
Self::default()
}
pub fn is_unknown(&self) -> bool {
self.start.offset == 0 && self.end.offset == 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct Position {
pub offset: u32,
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub struct Trivia {
pub leading: Vec<String>,
pub trailing: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Comment {
pub content: String,
pub is_block: bool,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct IRModule {
pub uri: String,
pub name: String,
pub template: Option<TemplateIR>,
pub script: Option<JsProgram>,
pub styles: Vec<StyleIR>,
pub custom_blocks: Vec<CustomBlock>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TemplateIR {
pub nodes: Vec<TemplateNodeIR>,
pub span: Span,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TemplateNodeIR {
Element(ElementIR),
Text(String, Span),
Interpolation(ExpressionIR),
Comment(String, Span),
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ElementIR {
pub tag: String,
pub attributes: Vec<AttributeIR>,
pub children: Vec<TemplateNodeIR>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AttributeIR {
pub name: String,
pub value: Option<String>,
pub value_ast: Option<JsExpr>,
pub is_directive: bool,
pub is_dynamic: bool,
pub span: Span,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ExpressionIR {
pub code: String,
pub span: Span,
pub ast: Option<JsExpr>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct StyleIR {
pub content: String,
pub lang: String,
pub span: Span,
pub scoped: bool,
pub module: bool,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CustomBlock {
pub name: String,
pub content: String,
pub attributes: HashMap<String, String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct JsProgram {
pub body: Vec<JsStmt>,
pub span: Span,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum JsStmt {
Expr(JsExpr, Span, Trivia),
VariableDecl {
kind: String,
id: String,
init: Option<JsExpr>,
span: Span,
type_ann: Option<String>,
},
FunctionDecl {
id: String,
params: Vec<String>,
body: Vec<JsStmt>,
span: Span,
return_type: Option<String>,
is_async: bool,
is_generator: bool,
},
Import {
specifiers: Vec<ImportSpecifier>,
source: String,
span: Span,
},
Export {
decl: Box<JsStmt>,
span: Span,
is_type: bool,
},
ExportDefault {
decl: Box<JsStmt>,
span: Span,
},
ExportAll {
source: String,
span: Span,
},
ExportNamed {
specifiers: Vec<String>,
source: Option<String>,
span: Span,
},
Return(JsExpr, Span, Trivia),
If {
test: JsExpr,
consequent: Vec<JsStmt>,
alternate: Option<Vec<JsStmt>>,
span: Span,
},
While {
test: JsExpr,
body: Vec<JsStmt>,
span: Span,
},
For {
init: Box<JsStmt>,
test: Option<JsExpr>,
update: Option<JsExpr>,
body: Vec<JsStmt>,
span: Span,
},
Block(Vec<JsStmt>, Span, Trivia),
Break(Span, Trivia),
Continue(Span, Trivia),
Other(String, Span, Trivia),
}
impl JsStmt {
pub fn span(&self) -> Span {
match self {
JsStmt::Expr(_, span, _) => *span,
JsStmt::VariableDecl { span, .. } => *span,
JsStmt::FunctionDecl { span, .. } => *span,
JsStmt::Import { span, .. } => *span,
JsStmt::Export { span, .. } => *span,
JsStmt::ExportDefault { span, .. } => *span,
JsStmt::ExportAll { span, .. } => *span,
JsStmt::ExportNamed { span, .. } => *span,
JsStmt::Return(_, span, _) => *span,
JsStmt::If { span, .. } => *span,
JsStmt::While { span, .. } => *span,
JsStmt::For { span, .. } => *span,
JsStmt::Block(_, span, _) => *span,
JsStmt::Break(span, _) => *span,
JsStmt::Continue(span, _) => *span,
JsStmt::Other(_, span, _) => *span,
}
}
pub fn trivia(&self) -> Trivia {
match self {
JsStmt::Expr(_, _, trivia) => trivia.clone(),
JsStmt::Return(_, _, trivia) => trivia.clone(),
JsStmt::Block(_, _, trivia) => trivia.clone(),
JsStmt::Break(_, trivia) => trivia.clone(),
JsStmt::Continue(_, trivia) => trivia.clone(),
JsStmt::Other(_, _, trivia) => trivia.clone(),
_ => Trivia::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ImportSpecifier {
Default {
name: String,
},
Named {
name: String,
alias: Option<String>,
},
Namespace {
alias: Option<String>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum JsExpr {
Literal(NargoValue, Span, Trivia),
Identifier(String, Span, Trivia),
Unary {
op: String,
argument: Box<JsExpr>,
span: Span,
trivia: Trivia,
},
Binary {
left: Box<JsExpr>,
op: String,
right: Box<JsExpr>,
span: Span,
trivia: Trivia,
},
Call {
callee: Box<JsExpr>,
args: Vec<JsExpr>,
span: Span,
trivia: Trivia,
},
Member {
object: Box<JsExpr>,
property: String,
computed: bool,
span: Span,
trivia: Trivia,
},
Object(HashMap<String, JsExpr>, Span, Trivia),
Array(Vec<JsExpr>, Span, Trivia),
ArrowFunction {
params: Vec<String>,
body: Box<JsExpr>,
span: Span,
trivia: Trivia,
},
Conditional {
test: Box<JsExpr>,
consequent: Box<JsExpr>,
alternate: Box<JsExpr>,
span: Span,
trivia: Trivia,
},
TemplateLiteral {
quasis: Vec<String>,
expressions: Vec<JsExpr>,
span: Span,
trivia: Trivia,
},
TseElement {
tag: String,
attributes: Vec<AttributeIR>,
children: Vec<JsExpr>,
span: Span,
trivia: Trivia,
},
Other(String, Span, Trivia),
}
impl JsExpr {
pub fn span(&self) -> Span {
match self {
JsExpr::Literal(_, span, _) => *span,
JsExpr::Identifier(_, span, _) => *span,
JsExpr::Unary { span, .. } => *span,
JsExpr::Binary { span, .. } => *span,
JsExpr::Call { span, .. } => *span,
JsExpr::Member { span, .. } => *span,
JsExpr::Object(_, span, _) => *span,
JsExpr::Array(_, span, _) => *span,
JsExpr::ArrowFunction { span, .. } => *span,
JsExpr::Conditional { span, .. } => *span,
JsExpr::TemplateLiteral { span, .. } => *span,
JsExpr::TseElement { span, .. } => *span,
JsExpr::Other(_, span, _) => *span,
}
}
pub fn trivia(&self) -> Trivia {
match self {
JsExpr::Literal(_, _, trivia) => trivia.clone(),
JsExpr::Identifier(_, _, trivia) => trivia.clone(),
JsExpr::Unary { trivia, .. } => trivia.clone(),
JsExpr::Binary { trivia, .. } => trivia.clone(),
JsExpr::Call { trivia, .. } => trivia.clone(),
JsExpr::Member { trivia, .. } => trivia.clone(),
JsExpr::Object(_, _, trivia) => trivia.clone(),
JsExpr::Array(_, _, trivia) => trivia.clone(),
JsExpr::ArrowFunction { trivia, .. } => trivia.clone(),
JsExpr::Conditional { trivia, .. } => trivia.clone(),
JsExpr::TemplateLiteral { trivia, .. } => trivia.clone(),
JsExpr::TseElement { trivia, .. } => trivia.clone(),
JsExpr::Other(_, _, trivia) => trivia.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NargoValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<NargoValue>),
Object(HashMap<String, NargoValue>),
Signal(String),
Raw(String),
Other(String),
}
impl Default for NargoValue {
fn default() -> Self {
NargoValue::Null
}
}