// Class diagram minimal grammar (phase 1).
grammar;
use crate::diagrams::class::{
Action, Relation, Tok, LINE_DOTTED, LINE_SOLID, REL_AGGREGATION, REL_COMPOSITION, REL_DEPENDENCY,
REL_EXTENSION, REL_LOLLIPOP, REL_NONE
};
extern {
type Location = usize;
type Error = crate::diagrams::class::LexError;
enum Tok {
Newline => Tok::Newline,
"classDiagram" => Tok::ClassDiagram,
Direction => Tok::Direction(<String>),
"class" => Tok::ClassKw,
"namespace" => Tok::NamespaceKw,
"note" => Tok::Note,
"note_for" => Tok::NoteFor,
"cssClass" => Tok::CssClass,
"style" => Tok::StyleKw,
"classDef" => Tok::ClassDefKw,
"click" => Tok::ClickKw,
"link" => Tok::LinkKw,
"callback" => Tok::CallbackKw,
"href" => Tok::HrefKw,
StructStart => Tok::StructStart,
StructStop => Tok::StructStop,
SquareStart => Tok::SquareStart,
SquareStop => Tok::SquareStop,
AnnotationStart => Tok::AnnotationStart,
AnnotationStop => Tok::AnnotationStop,
StyleSeparator => Tok::StyleSeparator,
Ext => Tok::Ext,
Dep => Tok::Dep,
Comp => Tok::Comp,
Agg => Tok::Agg,
Lollipop => Tok::Lollipop,
Line => Tok::Line,
DottedLine => Tok::DottedLine,
Label => Tok::Label(<String>),
Str => Tok::Str(<String>),
Name => Tok::Name(<String>),
Member => Tok::Member(<String>),
RestOfLine => Tok::RestOfLine(<String>),
LinkTarget => Tok::LinkTarget(<String>),
CallbackName => Tok::CallbackName(<String>),
CallbackArgs => Tok::CallbackArgs(<String>),
AccTitle => Tok::AccTitle(<String>),
AccDescr => Tok::AccDescr(<String>),
AccDescrMultiline => Tok::AccDescrMultiline(<String>),
}
}
pub Actions: Vec<Action> = {
<_n:Newlines> "classDiagram" <_n1:Newlines1> <s:Statements> => s
};
Statements: Vec<Action> = {
=> Vec::new(),
<s:Statement> <rest:StatementRest> => {
let mut v = s;
v.extend(rest);
v
}
};
StatementRest: Vec<Action> = {
<_n:Newlines1> <s:Statement> <rest:StatementRest> => {
let mut v = s;
v.extend(rest);
v
},
Newlines => Vec::new(),
};
Newlines: () = {
=> (),
Newline Newlines => (),
};
Newlines1: () = {
Newline Newlines => (),
};
Statement: Vec<Action> = {
<d:Direction> => vec![Action::SetDirection(d)],
<t:AccTitle> => vec![Action::SetAccTitle(t)],
<t:AccDescr> => vec![Action::SetAccDescr(t)],
<t:AccDescrMultiline> => vec![Action::SetAccDescr(t)],
<c:ClassStatement> => c,
<m:MemberStatement> => vec![m],
<a:AnnotationStatement> => vec![a],
<r:RelationStatement> => vec![Action::AddRelation { data: r }],
<r:RelationStatement> <lab:Label> => vec![Action::AddRelation { data: { let mut rr = r; rr.title = Some(lab); rr } }],
<n:NoteStatement> => vec![n],
<c:CssClassStatement> => vec![c],
<s:StyleStatement> => vec![s],
<d:ClassDefStatement> => vec![d],
<c:ClickStatement> => c,
<ns:NamespaceStatement> => ns,
};
ClassStatement: Vec<Action> = {
"class" <name:Name> <label:ClassLabel?> <css:CssShorthand?> <body:ClassBody?> => {
let mut v = vec![Action::AddClass { id: name.clone() }];
if let Some(lab) = label {
v.push(Action::SetClassLabel { id: name.clone(), label: lab });
}
if let Some(cls) = css {
v.push(Action::SetCssClass { ids: name.clone(), css_class: cls });
}
if let Some(members) = body {
v.push(Action::AddMembers { id: name, members });
}
v
}
};
ClassStatementWithId: (String, Vec<Action>) = {
"class" <name:Name> <label:ClassLabel?> <css:CssShorthand?> <body:ClassBody?> => {
let mut v = vec![Action::AddClass { id: name.clone() }];
if let Some(lab) = label {
v.push(Action::SetClassLabel { id: name.clone(), label: lab });
}
if let Some(cls) = css {
v.push(Action::SetCssClass { ids: name.clone(), css_class: cls });
}
if let Some(members) = body {
v.push(Action::AddMembers { id: name.clone(), members });
}
(name, v)
}
};
ClassLabel: String = {
SquareStart <s:Str> SquareStop => s
};
CssShorthand: String = {
StyleSeparator <c:Name> => c
};
ClassBody: Vec<String> = {
StructStart <m:Members> StructStop => m
};
Members: Vec<String> = {
=> Vec::new(),
<m:MemberLine> <rest:Members> => {
let mut v = rest;
v.push(m);
v
}
};
MemberLine: String = {
<m:Member> => m,
};
MemberStatement: Action = {
<name:Name> <lab:Label> => Action::AddMember { id: name, member: lab },
};
AnnotationStatement: Action = {
AnnotationStart <ann:Name> AnnotationStop <name:Name> => Action::AddAnnotation { id: name, annotation: ann },
};
NoteStatement: Action = {
"note_for" <name:Name> <t:Str> => Action::AddNote { class_id: Some(name), text: t },
"note" <t:Str> => Action::AddNote { class_id: None, text: t },
};
CssClassStatement: Action = {
"cssClass" <ids:Str> <cls:Name> => Action::SetCssClass { ids, css_class: cls },
};
StyleStatement: Action = {
"style" <id:Name> <raw:RestOfLine> => Action::SetCssStyle { id, raw },
};
ClassDefStatement: Action = {
"classDef" <id:Name> <raw:RestOfLine> => Action::DefineClass { id, raw },
};
ClickStatement: Vec<Action> = {
"link" <id:Name> <url:Str> => vec![
Action::SetLink { id: id.clone(), url, target: None },
],
"link" <id:Name> <url:Str> <t:LinkTarget> => vec![
Action::SetLink { id: id.clone(), url, target: Some(t) },
],
"link" <id:Name> <url:Str> <tt:Str> => vec![
Action::SetLink { id: id.clone(), url, target: None },
Action::SetTooltip { id, tooltip: tt },
],
"link" <id:Name> <url:Str> <tt:Str> <t:LinkTarget> => vec![
Action::SetLink { id: id.clone(), url, target: Some(t) },
Action::SetTooltip { id, tooltip: tt },
],
"click" <id:Name> "href" <url:Str> => vec![
Action::SetLink { id: id.clone(), url, target: None },
],
"click" <id:Name> "href" <url:Str> <t:LinkTarget> => vec![
Action::SetLink { id: id.clone(), url, target: Some(t) },
],
"click" <id:Name> "href" <url:Str> <tt:Str> => vec![
Action::SetLink { id: id.clone(), url, target: None },
Action::SetTooltip { id, tooltip: tt },
],
"click" <id:Name> "href" <url:Str> <tt:Str> <t:LinkTarget> => vec![
Action::SetLink { id: id.clone(), url, target: Some(t) },
Action::SetTooltip { id, tooltip: tt },
],
"callback" <id:Name> <fn_name:Str> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: None },
],
"callback" <id:Name> <fn_name:Str> <tt:Str> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: None },
Action::SetTooltip { id, tooltip: tt },
],
"click" <id:Name> <fn_name:CallbackName> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: None },
],
"click" <id:Name> <fn_name:CallbackName> <tt:Str> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: None },
Action::SetTooltip { id, tooltip: tt },
],
"click" <id:Name> <fn_name:CallbackName> <args:CallbackArgs> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: Some(args) },
],
"click" <id:Name> <fn_name:CallbackName> <args:CallbackArgs> <tt:Str> => vec![
Action::SetClickEvent { id: id.clone(), function: fn_name, args: Some(args) },
Action::SetTooltip { id, tooltip: tt },
],
};
NamespaceStatement: Vec<Action> = {
"namespace" <ns:Name> StructStart <_n:Newlines> <classes:NamespaceClasses> StructStop => {
let mut v = vec![Action::AddNamespace { id: ns.clone() }];
let (mut class_actions, class_ids) = classes;
v.append(&mut class_actions);
v.push(Action::AddClassesToNamespace { namespace: ns, class_ids });
v
}
};
NamespaceClasses: (Vec<Action>, Vec<String>) = {
=> (Vec::new(), Vec::new()),
<c:ClassStatementWithId> <rest:NamespaceClassesRest> => {
let mut actions = c.1;
let mut ids = vec![c.0];
actions.extend(rest.0);
ids.extend(rest.1);
(actions, ids)
}
};
NamespaceClassesRest: (Vec<Action>, Vec<String>) = {
<_n:Newlines1> <c:ClassStatementWithId> <rest:NamespaceClassesRest> => {
let mut actions = c.1;
let mut ids = vec![c.0];
actions.extend(rest.0);
ids.extend(rest.1);
(actions, ids)
},
Newlines => (Vec::new(), Vec::new()),
};
RelationStatement: crate::diagrams::class::RelationData = {
<a:Name> <rel:Relation> <b:Name> => crate::diagrams::class::RelationData {
id1: a,
id2: b,
relation: rel,
relation_title1: None,
relation_title2: None,
title: None,
},
<a:Name> <t1:Str> <rel:Relation> <b:Name> => crate::diagrams::class::RelationData {
id1: a,
id2: b,
relation: rel,
relation_title1: Some(t1),
relation_title2: None,
title: None,
},
<a:Name> <rel:Relation> <t2:Str> <b:Name> => crate::diagrams::class::RelationData {
id1: a,
id2: b,
relation: rel,
relation_title1: None,
relation_title2: Some(t2),
title: None,
},
<a:Name> <t1:Str> <rel:Relation> <t2:Str> <b:Name> => crate::diagrams::class::RelationData {
id1: a,
id2: b,
relation: rel,
relation_title1: Some(t1),
relation_title2: Some(t2),
title: None,
},
};
Relation: Relation = {
<t1:RelationType> <line:LineType> <t2:RelationType> => Relation { type1: t1, type2: t2, line_type: line },
<line:LineType> <t2:RelationType> => Relation { type1: REL_NONE, type2: t2, line_type: line },
<t1:RelationType> <line:LineType> => Relation { type1: t1, type2: REL_NONE, line_type: line },
<line:LineType> => Relation { type1: REL_NONE, type2: REL_NONE, line_type: line },
};
RelationType: i32 = {
Agg => REL_AGGREGATION,
Ext => REL_EXTENSION,
Comp => REL_COMPOSITION,
Dep => REL_DEPENDENCY,
Lollipop => REL_LOLLIPOP,
};
LineType: i32 = {
Line => LINE_SOLID,
DottedLine => LINE_DOTTED,
};