use super::functions::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span {
pub start: Pos,
pub end: Pos,
pub bytes: ByteRange,
}
impl Span {
pub fn new(start: Pos, end: Pos, bytes: ByteRange) -> Self {
Self { start, end, bytes }
}
pub fn dummy() -> Self {
Self {
start: Pos::start(),
end: Pos::start(),
bytes: ByteRange::empty(),
}
}
pub fn union(self, other: Span) -> Span {
Span {
start: if self.start.is_before(&other.start) {
self.start
} else {
other.start
},
end: if other.end.is_before(&self.end) {
self.end
} else {
other.end
},
bytes: self.bytes.union(other.bytes),
}
}
pub fn is_non_empty(&self) -> bool {
!self.bytes.is_empty()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct BinderExtExt2 {
pub name: String,
pub ty: Option<String>,
pub implicit: bool,
}
impl BinderExtExt2 {
#[allow(dead_code)]
pub fn explicit(name: &str, ty: Option<&str>) -> Self {
BinderExtExt2 {
name: name.to_string(),
ty: ty.map(|s| s.to_string()),
implicit: false,
}
}
#[allow(dead_code)]
pub fn implicit(name: &str, ty: Option<&str>) -> Self {
BinderExtExt2 {
name: name.to_string(),
ty: ty.map(|s| s.to_string()),
implicit: true,
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
let brackets = if self.implicit {
("{", "}")
} else {
("(", ")")
};
match &self.ty {
Some(t) => format!("{}{} : {}{}", brackets.0, self.name, t, brackets.1),
None => format!("{}{}{}", brackets.0, self.name, brackets.1),
}
}
}
#[derive(Clone, Debug)]
pub struct MacroExpansion {
pub macro_name: String,
pub span: ByteRange,
pub expansion_steps: u32,
}
impl MacroExpansion {
pub fn new(macro_name: impl Into<String>, span: ByteRange) -> Self {
Self {
macro_name: macro_name.into(),
span,
expansion_steps: 0,
}
}
pub fn increment(&mut self) {
self.expansion_steps += 1;
}
pub fn is_deep(&self) -> bool {
self.expansion_steps > 10
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Fixity {
InfixLeft,
InfixRight,
Infix,
Prefix,
Postfix,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Pos {
pub line: u32,
pub col: u32,
}
impl Pos {
pub fn new(line: u32, col: u32) -> Self {
Self { line, col }
}
pub fn start() -> Self {
Self { line: 1, col: 1 }
}
pub fn next_col(self) -> Self {
Self {
col: self.col + 1,
..self
}
}
pub fn next_line(self) -> Self {
Self {
line: self.line + 1,
col: 1,
}
}
pub fn is_before(&self, other: &Pos) -> bool {
(self.line, self.col) < (other.line, other.col)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ByteRange {
pub start: usize,
pub end: usize,
}
impl ByteRange {
pub fn new(start: usize, end: usize) -> Self {
assert!(start <= end, "ByteRange: start > end");
Self { start, end }
}
pub fn empty() -> Self {
Self { start: 0, end: 0 }
}
pub fn len(&self) -> usize {
self.end - self.start
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn union(self, other: ByteRange) -> ByteRange {
ByteRange {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
pub fn contains(&self, offset: usize) -> bool {
offset >= self.start && offset < self.end
}
pub fn slice<'a>(&self, src: &'a str) -> &'a str {
&src[self.start..self.end]
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct ComplexityMetric {
pub app_weight: u32,
pub lam_weight: u32,
pub leaf_weight: u32,
}
impl ComplexityMetric {
#[allow(dead_code)]
pub fn default_metric() -> Self {
ComplexityMetric {
app_weight: 2,
lam_weight: 3,
leaf_weight: 1,
}
}
#[allow(dead_code)]
pub fn compute(&self, node: &TreeNodeExt) -> u32 {
match node.kind {
SimpleNodeKindExt::Leaf => self.leaf_weight,
SimpleNodeKindExt::App => {
self.app_weight + node.children.iter().map(|c| self.compute(c)).sum::<u32>()
}
SimpleNodeKindExt::Lam => {
self.lam_weight + node.children.iter().map(|c| self.compute(c)).sum::<u32>()
}
_ => 1 + node.children.iter().map(|c| self.compute(c)).sum::<u32>(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct AstMetadata {
pub span: Option<ByteRange>,
pub type_hint: Option<String>,
pub synthetic: bool,
pub tags: Vec<String>,
}
impl AstMetadata {
pub fn empty() -> Self {
Self::default()
}
pub fn with_span(span: ByteRange) -> Self {
Self {
span: Some(span),
..Default::default()
}
}
pub fn synthetic() -> Self {
Self {
synthetic: true,
..Default::default()
}
}
pub fn add_tag(&mut self, tag: impl Into<String>) {
self.tags.push(tag.into());
}
pub fn has_tag(&self, tag: &str) -> bool {
self.tags.iter().any(|t| t == tag)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ImportDecl {
pub path: Vec<String>,
pub span: ByteRange,
}
impl ImportDecl {
pub fn new(path: Vec<String>, span: ByteRange) -> Self {
Self { path, span }
}
pub fn dotted_path(&self) -> String {
self.path.join(".")
}
pub fn is_root(&self) -> bool {
self.path.len() == 1
}
}
#[derive(Clone, Debug, Default)]
pub struct OperatorTable {
entries: Vec<NotationEntry>,
}
impl OperatorTable {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, entry: NotationEntry) {
self.entries.push(entry);
}
pub fn lookup(&self, symbol: &str) -> Vec<&NotationEntry> {
self.entries.iter().filter(|e| e.symbol == symbol).collect()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn infix_entries(&self) -> Vec<&NotationEntry> {
self.entries.iter().filter(|e| e.is_infix()).collect()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct BinderExt {
pub name: String,
pub ty: Option<String>,
pub implicit: bool,
}
impl BinderExt {
#[allow(dead_code)]
pub fn explicit(name: &str, ty: Option<&str>) -> Self {
BinderExt {
name: name.to_string(),
ty: ty.map(|s| s.to_string()),
implicit: false,
}
}
#[allow(dead_code)]
pub fn implicit(name: &str, ty: Option<&str>) -> Self {
BinderExt {
name: name.to_string(),
ty: ty.map(|s| s.to_string()),
implicit: true,
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
let inner = if let Some(ref ty) = self.ty {
format!("{} : {}", self.name, ty)
} else {
self.name.clone()
};
if self.implicit {
format!("{{{}}}", inner)
} else {
format!("({})", inner)
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct LetBindingExtExt2 {
pub name: String,
pub ty: Option<String>,
pub value: String,
pub body: String,
}
impl LetBindingExtExt2 {
#[allow(dead_code)]
pub fn new(name: &str, ty: Option<&str>, value: &str, body: &str) -> Self {
LetBindingExtExt2 {
name: name.to_string(),
ty: ty.map(|s| s.to_string()),
value: value.to_string(),
body: body.to_string(),
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
match &self.ty {
Some(t) => {
format!("let {} : {} := {}; {}", self.name, t, self.value, self.body)
}
None => format!("let {} := {}; {}", self.name, self.value, self.body),
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct TypeAnnotation {
pub expr: String,
pub ty: String,
}
impl TypeAnnotation {
#[allow(dead_code)]
pub fn new(expr: &str, ty: &str) -> Self {
TypeAnnotation {
expr: expr.to_string(),
ty: ty.to_string(),
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
format!("({} : {})", self.expr, self.ty)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UniverseLevel {
Zero,
Succ(Box<UniverseLevel>),
Max(Box<UniverseLevel>, Box<UniverseLevel>),
Var(String),
}
impl UniverseLevel {
#[allow(dead_code)]
pub fn concrete(&self) -> Option<usize> {
match self {
UniverseLevel::Zero => Some(0),
UniverseLevel::Succ(inner) => inner.concrete().map(|n| n + 1),
UniverseLevel::Max(a, b) => {
let ca = a.concrete()?;
let cb = b.concrete()?;
Some(ca.max(cb))
}
UniverseLevel::Var(_) => None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum AttrArg {
Ident(String),
Num(i64),
Str(String),
List(Vec<AttrArg>),
}
impl AttrArg {
pub fn ident(s: &str) -> Self {
AttrArg::Ident(s.to_string())
}
pub fn num(n: i64) -> Self {
AttrArg::Num(n)
}
pub fn str_arg(s: &str) -> Self {
AttrArg::Str(s.to_string())
}
pub fn as_ident(&self) -> Option<&str> {
match self {
AttrArg::Ident(s) => Some(s),
_ => None,
}
}
pub fn as_num(&self) -> Option<i64> {
match self {
AttrArg::Num(n) => Some(*n),
_ => None,
}
}
}
#[derive(Clone, Debug)]
pub struct NotationEntry {
pub symbol: String,
pub decl_name: String,
pub fixity: Fixity,
pub prec: Prec,
pub deprecated: bool,
}
impl NotationEntry {
pub fn new(symbol: &str, decl_name: &str, fixity: Fixity, prec: Prec) -> Self {
Self {
symbol: symbol.to_string(),
decl_name: decl_name.to_string(),
fixity,
prec,
deprecated: false,
}
}
pub fn deprecated(mut self) -> Self {
self.deprecated = true;
self
}
pub fn is_infix(&self) -> bool {
matches!(
self.fixity,
Fixity::InfixLeft | Fixity::InfixRight | Fixity::Infix
)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SimpleNodeKindExt {
Leaf,
App,
Lam,
Pi,
Let,
Sort,
Match,
Def,
Theorem,
Ann,
Proj,
Level,
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct LetBindingExt {
pub name: String,
pub ty: Option<String>,
pub value: String,
pub body: String,
}
impl LetBindingExt {
#[allow(dead_code)]
pub fn new(name: &str, value: &str, body: &str) -> Self {
LetBindingExt {
name: name.to_string(),
ty: None,
value: value.to_string(),
body: body.to_string(),
}
}
#[allow(dead_code)]
pub fn with_ty(mut self, ty: &str) -> Self {
self.ty = Some(ty.to_string());
self
}
#[allow(dead_code)]
pub fn format(&self) -> String {
if let Some(ref ty) = self.ty {
format!(
"let {} : {} := {} in {}",
self.name, ty, self.value, self.body
)
} else {
format!("let {} := {} in {}", self.name, self.value, self.body)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SurfaceIdent {
pub name: String,
pub span: ByteRange,
}
impl SurfaceIdent {
pub fn new(name: &str, span: ByteRange) -> Self {
Self {
name: name.to_string(),
span,
}
}
pub fn synthetic(name: &str) -> Self {
Self {
name: name.to_string(),
span: ByteRange::empty(),
}
}
pub fn is_synthetic(&self) -> bool {
self.span.is_empty()
}
pub fn is_anonymous(&self) -> bool {
self.name.starts_with('_')
}
pub fn is_qualified(&self) -> bool {
self.name.contains('.')
}
pub fn split_last(&self) -> Option<(&str, &str)> {
let pos = self.name.rfind('.')?;
Some((&self.name[..pos], &self.name[pos + 1..]))
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct Telescope {
pub binders: Vec<BinderExt>,
}
impl Telescope {
#[allow(dead_code)]
pub fn new() -> Self {
Telescope {
binders: Vec::new(),
}
}
#[allow(dead_code)]
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, b: BinderExt) -> Self {
self.binders.push(b);
self
}
#[allow(dead_code)]
pub fn format(&self) -> String {
self.binders
.iter()
.map(|b| b.format())
.collect::<Vec<_>>()
.join(" ")
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.binders.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.binders.is_empty()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct DeclHeaderExt {
pub name: String,
pub params: Vec<BinderExt>,
pub return_type: Option<String>,
}
impl DeclHeaderExt {
#[allow(dead_code)]
pub fn new(name: &str) -> Self {
DeclHeaderExt {
name: name.to_string(),
params: Vec::new(),
return_type: None,
}
}
#[allow(dead_code)]
pub fn add_param(mut self, b: BinderExt) -> Self {
self.params.push(b);
self
}
#[allow(dead_code)]
pub fn with_return_type(mut self, ty: &str) -> Self {
self.return_type = Some(ty.to_string());
self
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MatchExprExt {
pub scrutinee: String,
pub arms: Vec<(String, String)>,
}
impl MatchExprExt {
#[allow(dead_code)]
pub fn new(scrutinee: &str) -> Self {
MatchExprExt {
scrutinee: scrutinee.to_string(),
arms: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add_arm(mut self, pat: &str, body: &str) -> Self {
self.arms.push((pat.to_string(), body.to_string()));
self
}
#[allow(dead_code)]
pub fn format(&self) -> String {
let arms: Vec<String> = self
.arms
.iter()
.map(|(p, b)| format!(" | {} -> {}", p, b))
.collect();
format!("match {} with\n{}", self.scrutinee, arms.join("\n"))
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct WithPosExt<T> {
pub inner: T,
pub start: usize,
pub end: usize,
}
impl<T> WithPosExt<T> {
#[allow(dead_code)]
pub fn new(inner: T, start: usize, end: usize) -> Self {
WithPosExt { inner, start, end }
}
#[allow(dead_code)]
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> WithPosExt<U> {
WithPosExt {
inner: f(self.inner),
start: self.start,
end: self.end,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseError {
pub message: String,
pub pos: Pos,
pub hint: Option<String>,
}
impl ParseError {
pub fn new(message: impl Into<String>, pos: Pos) -> Self {
Self {
message: message.into(),
pos,
hint: None,
}
}
pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
self.hint = Some(hint.into());
self
}
pub fn display(&self) -> String {
let mut s = format!("error at {}: {}", self.pos, self.message);
if let Some(h) = &self.hint {
s.push_str(&format!("\n hint: {}", h));
}
s
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct FlatAstExt {
pub nodes: Vec<(SimpleNodeKindExt, String, usize)>,
}
impl FlatAstExt {
#[allow(dead_code)]
pub fn from_tree(root: &TreeNodeExt) -> Self {
let mut nodes = Vec::new();
flatten_tree_ext(root, 0, &mut nodes);
FlatAstExt { nodes }
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.nodes.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, Default)]
pub struct TelescopeExt2 {
pub binders: Vec<BinderExtExt2>,
}
impl TelescopeExt2 {
#[allow(dead_code)]
pub fn new() -> Self {
TelescopeExt2 {
binders: Vec::new(),
}
}
#[allow(dead_code)]
pub fn push(&mut self, b: BinderExtExt2) {
self.binders.push(b);
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.binders.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.binders.is_empty()
}
#[allow(dead_code)]
pub fn format(&self) -> String {
self.binders
.iter()
.map(|b| b.format())
.collect::<Vec<_>>()
.join(" ")
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MatchExprExtExt2 {
pub scrutinee: String,
pub arms: Vec<(String, String)>,
}
impl MatchExprExtExt2 {
#[allow(dead_code)]
pub fn new(scrutinee: &str, arms: Vec<(&str, &str)>) -> Self {
MatchExprExtExt2 {
scrutinee: scrutinee.to_string(),
arms: arms
.into_iter()
.map(|(p, b)| (p.to_string(), b.to_string()))
.collect(),
}
}
#[allow(dead_code)]
pub fn arm_count(&self) -> usize {
self.arms.len()
}
#[allow(dead_code)]
pub fn patterns(&self) -> Vec<&str> {
self.arms.iter().map(|(p, _)| p.as_str()).collect()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct TreeNodeExt {
pub kind: SimpleNodeKindExt,
pub label: String,
pub children: Vec<TreeNodeExt>,
}
impl TreeNodeExt {
#[allow(dead_code)]
pub fn leaf(label: &str) -> Self {
TreeNodeExt {
kind: SimpleNodeKindExt::Leaf,
label: label.to_string(),
children: Vec::new(),
}
}
#[allow(dead_code)]
pub fn app(func: TreeNodeExt, arg: TreeNodeExt) -> Self {
TreeNodeExt {
kind: SimpleNodeKindExt::App,
label: "@".to_string(),
children: vec![func, arg],
}
}
#[allow(dead_code)]
pub fn lam(binder: &str, body: TreeNodeExt) -> Self {
TreeNodeExt {
kind: SimpleNodeKindExt::Lam,
label: binder.to_string(),
children: vec![body],
}
}
#[allow(dead_code)]
pub fn depth(&self) -> usize {
if self.children.is_empty() {
return 0;
}
1 + self.children.iter().map(|c| c.depth()).max().unwrap_or(0)
}
#[allow(dead_code)]
pub fn size(&self) -> usize {
1 + self.children.iter().map(|c| c.size()).sum::<usize>()
}
#[allow(dead_code)]
pub fn visit<V: AstNodeVisitorExt>(&self, visitor: &mut V, depth: usize) {
let kind_str = format!("{:?}", self.kind);
visitor.visit_node(&kind_str, depth);
for child in &self.children {
child.visit(visitor, depth + 1);
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct TypeSynonym {
pub name: String,
pub params: Vec<String>,
pub def: String,
}
impl TypeSynonym {
#[allow(dead_code)]
pub fn new(name: &str, params: Vec<&str>, def: &str) -> Self {
TypeSynonym {
name: name.to_string(),
params: params.into_iter().map(|s| s.to_string()).collect(),
def: def.to_string(),
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
let params = self.params.join(" ");
if params.is_empty() {
format!("abbrev {} := {}", self.name, self.def)
} else {
format!("abbrev {} {} := {}", self.name, params, self.def)
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AstNodeKind {
Var,
Lam,
Pi,
App,
Let,
NatLit,
StrLit,
Sort,
Hole,
DefDecl,
TheoremDecl,
AxiomDecl,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TokenKindTag {
Ident,
Num,
Str,
Op,
Delim,
Eof,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Prec(pub u32);
impl Prec {
pub const ATOM: Prec = Prec(1024);
pub const APP: Prec = Prec(1000);
pub const MUL: Prec = Prec(70);
pub const ADD: Prec = Prec(65);
pub const CMP: Prec = Prec(50);
pub const MIN: Prec = Prec(0);
pub fn new(p: u32) -> Self {
Prec(p)
}
pub fn value(self) -> u32 {
self.0
}
pub fn tighter(self) -> Self {
Prec(self.0 + 1)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AnnotationKind {
Type,
Doc,
Derive,
Attr,
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct CountingVisitorExt {
pub counts: std::collections::HashMap<String, usize>,
pub depth: usize,
}
impl CountingVisitorExt {
#[allow(dead_code)]
pub fn new() -> Self {
CountingVisitorExt {
counts: std::collections::HashMap::new(),
depth: 0,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct NamespaceStack {
stack: Vec<String>,
}
impl NamespaceStack {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, ns: impl Into<String>) {
self.stack.push(ns.into());
}
pub fn pop(&mut self) -> Option<String> {
self.stack.pop()
}
pub fn current_path(&self) -> String {
self.stack.join(".")
}
pub fn qualify(&self, name: &str) -> String {
if self.stack.is_empty() {
name.to_string()
} else {
format!("{}.{}", self.current_path(), name)
}
}
pub fn depth(&self) -> usize {
self.stack.len()
}
pub fn is_top_level(&self) -> bool {
self.stack.is_empty()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct StructField {
pub name: String,
pub ty: String,
pub default: Option<String>,
}
impl StructField {
#[allow(dead_code)]
pub fn new(name: &str, ty: &str) -> Self {
StructField {
name: name.to_string(),
ty: ty.to_string(),
default: None,
}
}
#[allow(dead_code)]
pub fn with_default(mut self, v: &str) -> Self {
self.default = Some(v.to_string());
self
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DocComment {
pub text: String,
pub is_module_doc: bool,
pub span: ByteRange,
}
impl DocComment {
pub fn new(text: &str, span: ByteRange) -> Self {
Self {
text: text.to_string(),
is_module_doc: false,
span,
}
}
pub fn module_doc(text: &str) -> Self {
Self {
text: text.to_string(),
is_module_doc: true,
span: ByteRange::empty(),
}
}
pub fn first_line(&self) -> &str {
self.text.lines().next().unwrap_or("").trim()
}
pub fn is_empty(&self) -> bool {
self.text.trim().is_empty()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ScopeDecl {
Section(String),
Namespace(String),
End(String),
Open(Vec<String>),
}
impl ScopeDecl {
pub fn name(&self) -> Option<&str> {
match self {
ScopeDecl::Section(n) | ScopeDecl::Namespace(n) | ScopeDecl::End(n) => Some(n),
ScopeDecl::Open(_) => None,
}
}
pub fn opens_scope(&self) -> bool {
matches!(self, ScopeDecl::Section(_) | ScopeDecl::Namespace(_))
}
pub fn closes_scope(&self) -> bool {
matches!(self, ScopeDecl::End(_))
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct SubstTableExt {
pub mappings: Vec<(String, TreeNodeExt)>,
}
impl SubstTableExt {
#[allow(dead_code)]
pub fn new() -> Self {
SubstTableExt {
mappings: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add(&mut self, var: &str, replacement: TreeNodeExt) {
self.mappings.push((var.to_string(), replacement));
}
#[allow(dead_code)]
pub fn apply(&self, node: &TreeNodeExt) -> TreeNodeExt {
match node.kind {
SimpleNodeKindExt::Leaf => {
if let Some((_, replacement)) = self.mappings.iter().find(|(v, _)| v == &node.label)
{
replacement.clone()
} else {
node.clone()
}
}
_ => {
let new_children: Vec<TreeNodeExt> =
node.children.iter().map(|c| self.apply(c)).collect();
TreeNodeExt {
kind: node.kind.clone(),
label: node.label.clone(),
children: new_children,
}
}
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Visibility {
#[default]
Public,
Private,
Protected,
}
impl Visibility {
pub fn is_public(&self) -> bool {
matches!(self, Visibility::Public)
}
pub fn is_restricted(&self) -> bool {
!self.is_public()
}
}