1use anyhow::Result;
2use lex::{Span, Token, Tokenizer};
3use std::borrow::Cow;
4use std::collections::HashMap;
5use std::convert::TryFrom;
6use std::fmt;
7
8mod lex;
9mod resolve;
10
11pub use lex::validate_id;
12
13pub struct Ast<'a> {
14 pub items: Vec<Item<'a>>,
15}
16
17pub enum Item<'a> {
18 Use(Use<'a>),
19 Resource(Resource<'a>),
20 TypeDef(TypeDef<'a>),
21 Value(Value<'a>),
22 Interface(Interface<'a>),
23}
24
25pub struct Id<'a> {
26 pub name: Cow<'a, str>,
27 pub span: Span,
28}
29
30impl<'a> From<&'a str> for Id<'a> {
31 fn from(s: &'a str) -> Id<'a> {
32 Id {
33 name: s.into(),
34 span: Span { start: 0, end: 0 },
35 }
36 }
37}
38
39impl<'a> From<String> for Id<'a> {
40 fn from(s: String) -> Id<'a> {
41 Id {
42 name: s.into(),
43 span: Span { start: 0, end: 0 },
44 }
45 }
46}
47
48pub struct Use<'a> {
49 pub from: Vec<Id<'a>>,
50 names: Option<Vec<UseName<'a>>>,
51}
52
53struct UseName<'a> {
54 name: Id<'a>,
55 as_: Option<Id<'a>>,
56}
57
58pub struct Resource<'a> {
59 docs: Docs<'a>,
60 name: Id<'a>,
61 supertype: Option<Id<'a>>,
62 values: Vec<(bool, Value<'a>)>,
63}
64
65#[derive(Default)]
66struct Docs<'a> {
67 docs: Vec<Cow<'a, str>>,
68}
69
70pub struct TypeDef<'a> {
71 docs: Docs<'a>,
72 name: Id<'a>,
73 ty: Type<'a>,
74}
75
76enum Type<'a> {
77 Unit,
78 Bool,
79 U8,
80 U16,
81 U32,
82 U64,
83 S8,
84 S16,
85 S32,
86 S64,
87 Float32,
88 Float64,
89 Char,
90 String,
91 Handle(Id<'a>),
92 Name(Id<'a>),
93 List(Box<Type<'a>>),
94 Record(Record<'a>),
95 Flags(Flags<'a>),
96 Variant(Variant<'a>),
97 Tuple(Vec<Type<'a>>),
98 Enum(Enum<'a>),
99 Option(Box<Type<'a>>),
100 Expected(Expected<'a>),
101 Future(Box<Type<'a>>),
102 Stream(Stream<'a>),
103 Union(Union<'a>),
104}
105
106struct Record<'a> {
107 fields: Vec<Field<'a>>,
108}
109
110struct Field<'a> {
111 docs: Docs<'a>,
112 name: Id<'a>,
113 ty: Type<'a>,
114}
115
116struct Flags<'a> {
117 flags: Vec<Flag<'a>>,
118}
119
120struct Flag<'a> {
121 docs: Docs<'a>,
122 name: Id<'a>,
123}
124
125struct Variant<'a> {
126 span: Span,
127 cases: Vec<Case<'a>>,
128}
129
130struct Case<'a> {
131 docs: Docs<'a>,
132 name: Id<'a>,
133 ty: Option<Type<'a>>,
134}
135
136struct Enum<'a> {
137 span: Span,
138 cases: Vec<EnumCase<'a>>,
139}
140
141struct EnumCase<'a> {
142 docs: Docs<'a>,
143 name: Id<'a>,
144}
145
146struct Expected<'a> {
147 ok: Box<Type<'a>>,
148 err: Box<Type<'a>>,
149}
150
151struct Stream<'a> {
152 element: Box<Type<'a>>,
153 end: Box<Type<'a>>,
154}
155
156pub struct Value<'a> {
157 docs: Docs<'a>,
158 name: Id<'a>,
159 kind: ValueKind<'a>,
160}
161
162struct Union<'a> {
163 span: Span,
164 cases: Vec<UnionCase<'a>>,
165}
166
167struct UnionCase<'a> {
168 docs: Docs<'a>,
169 ty: Type<'a>,
170}
171
172enum ValueKind<'a> {
173 Function {
174 is_async: bool,
175 params: Vec<(Id<'a>, Type<'a>)>,
176 result: Type<'a>,
177 },
178 Global(Type<'a>),
179}
180
181#[allow(dead_code)] pub struct Interface<'a> {
183 docs: Docs<'a>,
184 name: Id<'a>,
185 items: Vec<Item<'a>>,
186}
187
188impl<'a> Ast<'a> {
189 pub fn parse(input: &'a str) -> Result<Ast<'a>> {
190 let mut lexer = Tokenizer::new(input)?;
191 let mut items = Vec::new();
192 while lexer.clone().next()?.is_some() {
193 let docs = parse_docs(&mut lexer)?;
194 items.push(Item::parse(&mut lexer, docs)?);
195 }
196 Ok(Ast { items })
197 }
198
199 pub fn resolve(
200 &self,
201 name: &str,
202 map: &HashMap<String, crate::Interface>,
203 ) -> Result<crate::Interface> {
204 let mut resolver = resolve::Resolver::default();
205 let instance = resolver.resolve(name, &self.items, map)?;
206 Ok(instance)
207 }
208}
209
210impl<'a> Item<'a> {
211 fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Item<'a>> {
212 match tokens.clone().next()? {
213 Some((_span, Token::Use)) => Use::parse(tokens, docs).map(Item::Use),
214 Some((_span, Token::Type)) => TypeDef::parse(tokens, docs).map(Item::TypeDef),
215 Some((_span, Token::Flags)) => TypeDef::parse_flags(tokens, docs).map(Item::TypeDef),
216 Some((_span, Token::Enum)) => TypeDef::parse_enum(tokens, docs).map(Item::TypeDef),
217 Some((_span, Token::Variant)) => {
218 TypeDef::parse_variant(tokens, docs).map(Item::TypeDef)
219 }
220 Some((_span, Token::Record)) => TypeDef::parse_record(tokens, docs).map(Item::TypeDef),
221 Some((_span, Token::Union)) => TypeDef::parse_union(tokens, docs).map(Item::TypeDef),
222 Some((_span, Token::Resource)) => Resource::parse(tokens, docs).map(Item::Resource),
223 Some((_span, Token::Interface)) => Interface::parse(tokens, docs).map(Item::Interface),
224 Some((_span, Token::Id)) | Some((_span, Token::ExplicitId)) => {
225 Value::parse(tokens, docs).map(Item::Value)
226 }
227 other => Err(err_expected(tokens, "`type`, `resource`, or `func`", other).into()),
228 }
229 }
230}
231
232impl<'a> Use<'a> {
233 fn parse(tokens: &mut Tokenizer<'a>, _docs: Docs<'a>) -> Result<Self> {
234 tokens.expect(Token::Use)?;
235 let mut names = None;
236 loop {
237 if names.is_none() {
238 if tokens.eat(Token::Star)? {
239 break;
240 }
241 tokens.expect(Token::LeftBrace)?;
242 names = Some(Vec::new());
243 }
244 let names = names.as_mut().unwrap();
245 let mut name = UseName {
246 name: parse_id(tokens)?,
247 as_: None,
248 };
249 if tokens.eat(Token::As)? {
250 name.as_ = Some(parse_id(tokens)?);
251 }
252 names.push(name);
253 if !tokens.eat(Token::Comma)? {
254 break;
255 }
256 }
257 if names.is_some() {
258 tokens.expect(Token::RightBrace)?;
259 }
260 tokens.expect(Token::From_)?;
261 let mut from = vec![parse_id(tokens)?];
262 while tokens.eat(Token::Colon)? {
263 tokens.expect_raw(Token::Colon)?;
264 from.push(parse_id(tokens)?);
265 }
266 Ok(Use { from, names })
267 }
268}
269
270impl<'a> TypeDef<'a> {
271 fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
272 tokens.expect(Token::Type)?;
273 let name = parse_id(tokens)?;
274 tokens.expect(Token::Equals)?;
275 let ty = Type::parse(tokens)?;
276 Ok(TypeDef { docs, name, ty })
277 }
278
279 fn parse_flags(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
280 tokens.expect(Token::Flags)?;
281 let name = parse_id(tokens)?;
282 let ty = Type::Flags(Flags {
283 flags: parse_list(
284 tokens,
285 Token::LeftBrace,
286 Token::RightBrace,
287 |docs, tokens| {
288 let name = parse_id(tokens)?;
289 Ok(Flag { docs, name })
290 },
291 )?,
292 });
293 Ok(TypeDef { docs, name, ty })
294 }
295
296 fn parse_record(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
297 tokens.expect(Token::Record)?;
298 let name = parse_id(tokens)?;
299 let ty = Type::Record(Record {
300 fields: parse_list(
301 tokens,
302 Token::LeftBrace,
303 Token::RightBrace,
304 |docs, tokens| {
305 let name = parse_id(tokens)?;
306 tokens.expect(Token::Colon)?;
307 let ty = Type::parse(tokens)?;
308 Ok(Field { docs, name, ty })
309 },
310 )?,
311 });
312 Ok(TypeDef { docs, name, ty })
313 }
314
315 fn parse_variant(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
316 tokens.expect(Token::Variant)?;
317 let name = parse_id(tokens)?;
318 let ty = Type::Variant(Variant {
319 span: name.span,
320 cases: parse_list(
321 tokens,
322 Token::LeftBrace,
323 Token::RightBrace,
324 |docs, tokens| {
325 let name = parse_id(tokens)?;
326 let ty = if tokens.eat(Token::LeftParen)? {
327 let ty = Type::parse(tokens)?;
328 tokens.expect(Token::RightParen)?;
329 Some(ty)
330 } else {
331 None
332 };
333 Ok(Case { docs, name, ty })
334 },
335 )?,
336 });
337 Ok(TypeDef { docs, name, ty })
338 }
339
340 fn parse_union(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
341 tokens.expect(Token::Union)?;
342 let name = parse_id(tokens)?;
343 let ty = Type::Union(Union {
344 span: name.span,
345 cases: parse_list(
346 tokens,
347 Token::LeftBrace,
348 Token::RightBrace,
349 |docs, tokens| {
350 let ty = Type::parse(tokens)?;
351 Ok(UnionCase { docs, ty })
352 },
353 )?,
354 });
355 Ok(TypeDef { docs, name, ty })
356 }
357
358 fn parse_enum(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
359 tokens.expect(Token::Enum)?;
360 let name = parse_id(tokens)?;
361 let ty = Type::Enum(Enum {
362 span: name.span,
363 cases: parse_list(
364 tokens,
365 Token::LeftBrace,
366 Token::RightBrace,
367 |docs, tokens| {
368 let name = parse_id(tokens)?;
369 Ok(EnumCase { docs, name })
370 },
371 )?,
372 });
373 Ok(TypeDef { docs, name, ty })
374 }
375}
376
377impl<'a> Resource<'a> {
378 fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
379 tokens.expect(Token::Resource)?;
380 let name = parse_id(tokens)?;
381 let supertype = if tokens.eat(Token::Implements)? {
382 Some(parse_id(tokens)?)
383 } else {
384 None
385 };
386 let mut values = Vec::new();
387 if tokens.eat(Token::LeftBrace)? {
388 loop {
389 let docs = parse_docs(tokens)?;
390 if tokens.eat(Token::RightBrace)? {
391 break;
392 }
393 let statik = tokens.eat(Token::Static)?;
394 values.push((statik, Value::parse(tokens, docs)?));
395 }
396 }
397 Ok(Resource {
398 docs,
399 name,
400 supertype,
401 values,
402 })
403 }
404}
405
406impl<'a> Value<'a> {
407 fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
408 let name = parse_id(tokens)?;
409 tokens.expect(Token::Colon)?;
410
411 let kind = if tokens.eat(Token::Func)? {
412 parse_func(tokens, false)?
413 } else if tokens.eat(Token::Async)? {
414 tokens.expect(Token::Func)?;
415 parse_func(tokens, true)?
416 } else {
417 ValueKind::Global(Type::parse(tokens)?)
418 };
419 return Ok(Value { docs, name, kind });
420
421 fn parse_func<'a>(tokens: &mut Tokenizer<'a>, is_async: bool) -> Result<ValueKind<'a>> {
422 let params = parse_list(
423 tokens,
424 Token::LeftParen,
425 Token::RightParen,
426 |_docs, tokens| {
427 let name = parse_id(tokens)?;
428 tokens.expect(Token::Colon)?;
429 let ty = Type::parse(tokens)?;
430 Ok((name, ty))
431 },
432 )?;
433 let result = if tokens.eat(Token::RArrow)? {
434 Type::parse(tokens)?
435 } else {
436 Type::Unit
437 };
438 Ok(ValueKind::Function {
439 is_async,
440 params,
441 result,
442 })
443 }
444 }
445}
446
447fn parse_id<'a>(tokens: &mut Tokenizer<'a>) -> Result<Id<'a>> {
448 match tokens.next()? {
449 Some((span, Token::Id)) => Ok(Id {
450 name: tokens.parse_id(span)?.into(),
451 span,
452 }),
453 Some((span, Token::ExplicitId)) => Ok(Id {
454 name: tokens.parse_explicit_id(span)?.into(),
455 span,
456 }),
457 other => Err(err_expected(tokens, "an identifier or string", other).into()),
458 }
459}
460
461fn parse_docs<'a>(tokens: &mut Tokenizer<'a>) -> Result<Docs<'a>> {
462 let mut docs = Docs::default();
463 let mut clone = tokens.clone();
464 while let Some((span, token)) = clone.next_raw()? {
465 match token {
466 Token::Whitespace => {}
467 Token::Comment => docs.docs.push(tokens.get_span(span).into()),
468 _ => break,
469 };
470 *tokens = clone.clone();
471 }
472 Ok(docs)
473}
474
475impl<'a> Type<'a> {
476 fn parse(tokens: &mut Tokenizer<'a>) -> Result<Self> {
477 match tokens.next()? {
478 Some((_span, Token::U8)) => Ok(Type::U8),
479 Some((_span, Token::U16)) => Ok(Type::U16),
480 Some((_span, Token::U32)) => Ok(Type::U32),
481 Some((_span, Token::U64)) => Ok(Type::U64),
482 Some((_span, Token::S8)) => Ok(Type::S8),
483 Some((_span, Token::S16)) => Ok(Type::S16),
484 Some((_span, Token::S32)) => Ok(Type::S32),
485 Some((_span, Token::S64)) => Ok(Type::S64),
486 Some((_span, Token::Float32)) => Ok(Type::Float32),
487 Some((_span, Token::Float64)) => Ok(Type::Float64),
488 Some((_span, Token::Char)) => Ok(Type::Char),
489 Some((_span, Token::Handle)) => {
490 let name = parse_id(tokens)?;
491 Ok(Type::Handle(name))
492 }
493
494 Some((_span, Token::Tuple)) => {
496 let types = parse_list(
497 tokens,
498 Token::LessThan,
499 Token::GreaterThan,
500 |_docs, tokens| Type::parse(tokens),
501 )?;
502 Ok(Type::Tuple(types))
503 }
504
505 Some((_span, Token::Unit)) => Ok(Type::Unit),
506 Some((_span, Token::Bool)) => Ok(Type::Bool),
507 Some((_span, Token::String_)) => Ok(Type::String),
508
509 Some((_span, Token::List)) => {
511 tokens.expect(Token::LessThan)?;
512 let ty = Type::parse(tokens)?;
513 tokens.expect(Token::GreaterThan)?;
514 Ok(Type::List(Box::new(ty)))
515 }
516
517 Some((_span, Token::Option_)) => {
519 tokens.expect(Token::LessThan)?;
520 let ty = Type::parse(tokens)?;
521 tokens.expect(Token::GreaterThan)?;
522 Ok(Type::Option(Box::new(ty)))
523 }
524
525 Some((_span, Token::Expected)) => {
527 tokens.expect(Token::LessThan)?;
528 let ok = Box::new(Type::parse(tokens)?);
529 tokens.expect(Token::Comma)?;
530 let err = Box::new(Type::parse(tokens)?);
531 tokens.expect(Token::GreaterThan)?;
532 Ok(Type::Expected(Expected { ok, err }))
533 }
534
535 Some((_span, Token::Future)) => {
537 tokens.expect(Token::LessThan)?;
538 let ty = Box::new(Type::parse(tokens)?);
539 tokens.expect(Token::GreaterThan)?;
540 Ok(Type::Future(ty))
541 }
542
543 Some((_span, Token::Stream)) => {
545 tokens.expect(Token::LessThan)?;
546 let element = Box::new(Type::parse(tokens)?);
547 tokens.expect(Token::Comma)?;
548 let end = Box::new(Type::parse(tokens)?);
549 tokens.expect(Token::GreaterThan)?;
550 Ok(Type::Stream(Stream { element, end }))
551 }
552
553 Some((span, Token::Id)) => Ok(Type::Name(Id {
555 name: tokens.parse_id(span)?.into(),
556 span,
557 })),
558 Some((span, Token::ExplicitId)) => Ok(Type::Name(Id {
560 name: tokens.parse_explicit_id(span)?.into(),
561 span,
562 })),
563
564 other => Err(err_expected(tokens, "a type", other).into()),
565 }
566 }
567}
568
569impl<'a> Interface<'a> {
570 fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result<Self> {
571 tokens.expect(Token::Interface)?;
572 let name = parse_id(tokens)?;
573 tokens.expect(Token::LeftBrace)?;
574 let mut items = Vec::new();
575 loop {
576 let docs = parse_docs(tokens)?;
577 if tokens.eat(Token::RightBrace)? {
578 break;
579 }
580 items.push(Item::parse(tokens, docs)?);
581 }
582 Ok(Interface { docs, name, items })
583 }
584}
585
586fn parse_list<'a, T>(
587 tokens: &mut Tokenizer<'a>,
588 start: Token,
589 end: Token,
590 mut parse: impl FnMut(Docs<'a>, &mut Tokenizer<'a>) -> Result<T>,
591) -> Result<Vec<T>> {
592 tokens.expect(start)?;
593 let mut items = Vec::new();
594 loop {
595 let docs = parse_docs(tokens)?;
597
598 if tokens.eat(end)? {
600 break;
601 }
602
603 let item = parse(docs, tokens)?;
604 items.push(item);
605
606 if !tokens.eat(Token::Comma)? {
609 tokens.expect(end)?;
610 break;
611 }
612 }
613 Ok(items)
614}
615
616fn err_expected(
617 tokens: &Tokenizer<'_>,
618 expected: &'static str,
619 found: Option<(Span, Token)>,
620) -> Error {
621 match found {
622 Some((span, token)) => Error {
623 span,
624 msg: format!("expected {}, found {}", expected, token.describe()),
625 },
626 None => Error {
627 span: Span {
628 start: u32::try_from(tokens.input().len()).unwrap(),
629 end: u32::try_from(tokens.input().len()).unwrap(),
630 },
631 msg: format!("expected {}, found eof", expected),
632 },
633 }
634}
635
636#[derive(Debug)]
637struct Error {
638 span: Span,
639 msg: String,
640}
641
642impl fmt::Display for Error {
643 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
644 self.msg.fmt(f)
645 }
646}
647
648impl std::error::Error for Error {}
649
650pub fn rewrite_error(err: &mut anyhow::Error, file: &str, contents: &str) {
651 let parse = match err.downcast_mut::<Error>() {
652 Some(err) => err,
653 None => return lex::rewrite_error(err, file, contents),
654 };
655 let msg = highlight_err(
656 parse.span.start as usize,
657 Some(parse.span.end as usize),
658 file,
659 contents,
660 &parse.msg,
661 );
662 *err = anyhow::anyhow!("{}", msg);
663}
664
665fn highlight_err(
666 start: usize,
667 end: Option<usize>,
668 file: &str,
669 input: &str,
670 err: impl fmt::Display,
671) -> String {
672 let (line, col) = linecol_in(start, input);
673 let snippet = input.lines().nth(line).unwrap_or("");
674 let mut msg = format!(
675 "\
676{err}
677 --> {file}:{line}:{col}
678 |
679 {line:4} | {snippet}
680 | {marker:>0$}",
681 col + 1,
682 file = file,
683 line = line + 1,
684 col = col + 1,
685 err = err,
686 snippet = snippet,
687 marker = "^",
688 );
689 if let Some(end) = end {
690 if let Some(s) = input.get(start..end) {
691 for _ in s.chars().skip(1) {
692 msg.push('-');
693 }
694 }
695 }
696 return msg;
697
698 fn linecol_in(pos: usize, text: &str) -> (usize, usize) {
699 let mut cur = 0;
700 for (i, line) in text.split_terminator('\n').enumerate() {
704 if cur + line.len() + 1 > pos {
705 return (i, pos - cur);
706 }
707 cur += line.len() + 1;
708 }
709 (text.lines().count(), 0)
710 }
711}