1use gramatika::{
4 arcstr::literal_substr, Parse, ParseStreamer, Span, Spanned, SpannedError, Token as _,
5};
6use lazy_static::lazy_static;
7
8mod alias;
9mod func;
10pub mod import;
11pub mod legacy;
12mod struc;
13mod var;
14
15use crate::{common::AttributeList, ParseStream, Token, TokenKind};
16
17pub use self::{
18 alias::TypeAliasDecl,
19 func::{FunctionDecl, ParamDecl},
20 import::{
21 ImportDecl, ImportPath, ImportPathBlock, ImportPathDecl, ImportPathLeaf,
22 NamespacedImportPath,
23 },
24 struc::{FieldDecl, StructBody, StructDecl},
25 var::VarDecl,
26};
27
28#[derive(Clone, DebugLisp)]
29pub enum Decl {
30 Var(VarDecl),
31 Const(VarDecl),
32 TypeAlias(TypeAliasDecl),
33 Struct(StructDecl),
34 Field(FieldDecl),
35 Function(FunctionDecl),
36 Param(ParamDecl),
37 Extension(legacy::ExtensionDecl), ImportPath(ImportPathDecl),
39 Import(ImportDecl),
40 Module(legacy::ModuleDecl), }
42
43lazy_static! {
44 static ref ERR_TOKEN: Token = Token::Ident(literal_substr!("ERROR"), Span::default());
46}
47
48impl Decl {
49 pub fn name(&self) -> &Token {
50 match self {
51 Decl::Var(decl) | Decl::Const(decl) => &decl.name,
52 Decl::TypeAlias(decl) => &decl.name,
53 Decl::Struct(decl) => &decl.name,
54 Decl::Field(decl) => &decl.name,
55 Decl::Function(decl) => &decl.name,
56 Decl::Param(decl) => &decl.name,
57 Decl::Extension(decl) => &decl.name,
58 Decl::ImportPath(decl) => decl.name(),
59 Decl::Import(_) => &ERR_TOKEN,
60 Decl::Module(decl) => &decl.name,
61 }
62 }
63
64 pub fn attributes(&self) -> Option<&AttributeList> {
65 match self {
66 Decl::Var(decl) => decl.attributes.as_ref(),
67 Decl::Const(decl) => decl.attributes.as_ref(),
68 Decl::TypeAlias(_) => None,
69 Decl::Struct(decl) => decl.attributes.as_ref(),
70 Decl::Field(decl) => decl.attributes.as_ref(),
71 Decl::Function(decl) => decl.attributes.as_ref(),
72 Decl::Param(decl) => decl.attributes.as_ref(),
73 Decl::Extension(_) => None,
74 Decl::ImportPath(_) => None,
75 Decl::Import(_) => None,
76 Decl::Module(_) => None,
77 }
78 }
79}
80
81impl Parse for Decl {
82 type Stream = ParseStream;
83
84 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
85 use TokenKind::*;
86
87 match input.peek() {
88 Some(token) => match token.as_matchable() {
89 (Punct, "@", _) => {
90 let attributes = input.parse::<AttributeList>()?;
91
92 match input.parse::<Decl>()? {
93 Decl::Var(mut inner) => {
94 inner.attributes = Some(attributes);
95 Ok(Decl::Var(inner))
96 }
97 Decl::Const(mut inner) => {
98 inner.attributes = Some(attributes);
99 Ok(Decl::Const(inner))
100 }
101 Decl::Struct(mut inner) => {
102 inner.attributes = Some(attributes);
103 Ok(Decl::Struct(inner))
104 }
105 Decl::Function(mut inner) => {
106 inner.attributes = Some(attributes);
107 Ok(Decl::Function(inner))
108 }
109 _ => Err(SpannedError {
110 message: "Attributes are not valid in this position".into(),
111 span: Some(attributes.span()),
112 source: input.source(),
113 }),
114 }
115 }
116 (Keyword, "var", _) => Ok(Decl::Var(input.parse()?)),
117 (Keyword, "let" | "const" | "override", _) => Ok(Decl::Const(input.parse()?)),
118 (Keyword, "alias", _) => Ok(Decl::TypeAlias(input.parse()?)),
119 (Keyword, "struct", _) => Ok(Decl::Struct(input.parse()?)),
120 (Keyword, "fn", _) => Ok(Decl::Function(input.parse()?)),
121 (Keyword, "enable", _) => Ok(Decl::Extension(input.parse()?)),
122 (Directive, "#define_import_path", _) => Ok(Decl::ImportPath(input.parse()?)),
123 (Directive, "#import", _) => Ok(Decl::Import(input.parse()?)),
124 (Keyword, "import", _) => Ok(Decl::Module(input.parse()?)),
125 (_, _, span) => Err(SpannedError {
126 message: "Expected `var`, `let`, `const`, `override`, `alias`, \
127 `struct`, `fn`, `enable`, or `import`"
128 .into(),
129 span: Some(span),
130 source: input.source(),
131 }),
132 },
133 None => Err(SpannedError {
134 message: "Unexpected end of input".into(),
135 source: input.source(),
136 span: input.prev().map(|token| token.span()),
137 }),
138 }
139 }
140}
141
142impl Spanned for Decl {
143 fn span(&self) -> Span {
144 use Decl::*;
145
146 match self {
147 Var(inner) => inner.span(),
148 Const(inner) => inner.span(),
149 TypeAlias(inner) => inner.span(),
150 Struct(inner) => inner.span(),
151 Field(inner) => inner.span(),
152 Function(inner) => inner.span(),
153 Param(inner) => inner.span(),
154 Extension(inner) => inner.span(),
155 ImportPath(inner) => inner.span(),
156 Import(inner) => inner.span(),
157 Module(inner) => inner.span(),
158 }
159 }
160}