use std::collections::HashMap;
use super::super::error::ErrorCode;
use serde::{Serialize, Deserialize};
use super::super::parser::{rainlangdocument::RainlangDocument, raindocument::RainDocument};
#[cfg(feature = "js-api")]
use tsify::Tsify;
#[cfg_attr(feature = "js-api", tsify::declare)]
pub type Offsets = [usize; 2];
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct ParsedItem(pub String, pub Offsets);
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Problem {
pub msg: String,
pub position: Offsets,
pub code: ErrorCode,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Literal {
pub value: String,
pub position: Offsets,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub lhs_alias: Option<Vec<Alias>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct OpcodeDetails {
pub name: String,
pub description: String,
pub position: Offsets,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct OperandArgItem {
pub value: Option<String>,
pub name: String,
pub position: Offsets,
pub description: String,
pub binding_id: Option<(String, bool)>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct OperandArg {
pub position: Offsets,
pub args: Vec<OperandArgItem>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Opcode {
pub opcode: OpcodeDetails,
pub operand: Option<u8>,
pub output: Option<u8>,
pub position: Offsets,
pub parens: Offsets,
pub inputs: Vec<Node>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub lhs_alias: Option<Vec<Alias>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub operand_args: Option<OperandArg>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Alias {
pub name: String,
pub position: Offsets,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub lhs_alias: Option<Vec<Alias>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Comment {
pub comment: String,
pub position: Offsets,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct ImportConfiguration {
pub problems: Vec<Problem>,
pub groups: Vec<(ParsedItem, Option<ParsedItem>)>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct ImportSequence {
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(type = "IRainDocument", optional))]
pub dotrain: Option<RainDocument>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Import {
pub name: String,
pub name_position: Offsets,
pub hash: String,
pub hash_position: Offsets,
pub position: Offsets,
pub problems: Vec<Problem>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub configuration: Option<ImportConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "js-api", tsify(optional))]
pub sequence: Option<ImportSequence>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct PragmaStatement {
pub keyword: Offsets,
pub sources: Vec<(ParsedItem, Option<String>)>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub enum Node {
Literal(Literal),
Opcode(Opcode),
Alias(Alias),
}
impl Node {
pub fn position(&self) -> Offsets {
match self {
Node::Literal(v) => v.position,
Node::Opcode(op) => op.position,
Node::Alias(a) => a.position,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct RainlangLine {
pub nodes: Vec<Node>,
pub position: Offsets,
pub aliases: Vec<Alias>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct RainlangSource {
pub lines: Vec<RainlangLine>,
pub position: Offsets,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct RainlangAST(Vec<RainlangSource>);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct ElidedBindingItem {
pub msg: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct LiteralBindingItem {
pub value: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct QuoteBindingItem {
pub quote: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub enum BindingItem {
Elided(ElidedBindingItem),
Literal(LiteralBindingItem),
Exp(RainlangDocument),
Quote(QuoteBindingItem),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct Binding {
pub name: String,
pub name_position: Offsets,
pub content: String,
pub content_position: Offsets,
pub position: Offsets,
pub problems: Vec<Problem>,
pub item: BindingItem,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct NamespaceLeaf {
pub hash: String,
pub import_index: isize,
pub element: Binding,
}
impl NamespaceLeaf {
pub fn is_elided_binding(&self) -> bool {
matches!(
self.element,
Binding {
item: BindingItem::Elided(_),
..
}
)
}
pub fn unwrap_elided_binding(&self) -> &String {
if let BindingItem::Elided(e) = &self.element.item {
&e.msg
} else {
panic!("not an elided binding")
}
}
pub fn is_constant_binding(&self) -> bool {
matches!(
self.element,
Binding {
item: BindingItem::Literal(_),
..
}
)
}
pub fn unwrap_constant_binding(&self) -> &String {
if let BindingItem::Literal(c) = &self.element.item {
&c.value
} else {
panic!("not a constant binding")
}
}
pub fn is_exp_binding(&self) -> bool {
matches!(
self.element,
Binding {
item: BindingItem::Exp(_),
..
}
)
}
pub fn unwrap_exp_binding(&self) -> &RainlangDocument {
if let BindingItem::Exp(e) = &self.element.item {
e
} else {
panic!("not an exp binding")
}
}
pub fn is_quote_binding(&self) -> bool {
matches!(
self.element,
Binding {
item: BindingItem::Quote(_),
..
}
)
}
pub fn unwrap_quote_binding(&self) -> &QuoteBindingItem {
if let BindingItem::Quote(q) = &self.element.item {
q
} else {
panic!("not a quote binding")
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "js-api", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub enum NamespaceItem {
Leaf(NamespaceLeaf),
Node(Namespace),
}
impl NamespaceItem {
pub fn is_leaf(&self) -> bool {
matches!(self, NamespaceItem::Leaf(_))
}
pub fn unwrap_leaf(&self) -> &NamespaceLeaf {
match self {
NamespaceItem::Leaf(leaf) => leaf,
NamespaceItem::Node(_) => panic!("not a leaf"),
}
}
pub fn unwrap_node(&self) -> &Namespace {
match self {
NamespaceItem::Leaf(_) => panic!("not a node"),
NamespaceItem::Node(node) => node,
}
}
pub fn unwrap_node_mut(&mut self) -> &mut Namespace {
match self {
NamespaceItem::Leaf(_) => panic!("not a node"),
NamespaceItem::Node(node) => node,
}
}
pub fn is_elided_binding(&self) -> bool {
matches!(
self,
NamespaceItem::Leaf(NamespaceLeaf {
element: Binding {
item: BindingItem::Elided(_),
..
},
..
})
)
}
pub fn unwrap_elided_binding(&self) -> &String {
if let NamespaceItem::Leaf(NamespaceLeaf {
element:
Binding {
item: BindingItem::Elided(e),
..
},
..
}) = self
{
&e.msg
} else {
panic!("not an elided binding")
}
}
pub fn is_constant_binding(&self) -> bool {
matches!(
self,
NamespaceItem::Leaf(NamespaceLeaf {
element: Binding {
item: BindingItem::Literal(_),
..
},
..
})
)
}
pub fn unwrap_constant_binding(&self) -> &String {
if let NamespaceItem::Leaf(NamespaceLeaf {
element:
Binding {
item: BindingItem::Literal(c),
..
},
..
}) = self
{
&c.value
} else {
panic!("not a constant binding")
}
}
pub fn is_exp_binding(&self) -> bool {
matches!(
self,
NamespaceItem::Leaf(NamespaceLeaf {
element: Binding {
item: BindingItem::Exp(_),
..
},
..
})
)
}
pub fn unwrap_exp_binding(&self) -> &RainlangDocument {
if let NamespaceItem::Leaf(NamespaceLeaf {
element:
Binding {
item: BindingItem::Exp(e),
..
},
..
}) = self
{
e
} else {
panic!("not an exp binding")
}
}
pub fn is_quote_binding(&self) -> bool {
matches!(
self,
NamespaceItem::Leaf(NamespaceLeaf {
element: Binding {
item: BindingItem::Quote(_),
..
},
..
})
)
}
pub fn unwrap_quote_binding(&self) -> &QuoteBindingItem {
if let NamespaceItem::Leaf(NamespaceLeaf {
element:
Binding {
item: BindingItem::Quote(q),
..
},
..
}) = self
{
q
} else {
panic!("not a quote binding")
}
}
}
#[cfg_attr(feature = "js-api", tsify::declare)]
pub type Namespace = HashMap<String, NamespaceItem>;