Actually just three programming languages in a trenchcoat
at main 101 lines 4.2 kB view raw
1use super::*; 2use crate::{Parser, Spanned}; 3use source_span::Span; 4use trilogy_scanner::TokenType::*; 5 6/// A complete Trilogy document. 7/// 8/// Similar to a module, but without a module declaration. 9#[derive(Clone, Debug)] 10pub struct Document { 11 /// The inner documentation of this document, intended to document the whole file. 12 pub documentation: Option<Documentation>, 13 /// The definitions contained within this file. 14 pub definitions: Vec<Definition>, 15 pub span: Span, 16} 17 18impl Spanned for Document { 19 fn span(&self) -> Span { 20 self.span 21 } 22} 23 24impl Document { 25 fn synchronize(parser: &mut Parser) { 26 parser.synchronize([ 27 DocOuter, KwType, KwFunc, KwProc, KwRule, KwSlot, KwExport, KwImport, EndOfFile, 28 ]); 29 } 30 31 pub(crate) fn parse(parser: &mut Parser) -> Self { 32 let documentation = Documentation::parse_inner(parser); 33 34 let mut definitions = vec![]; 35 loop { 36 match Definition::parse_in_document(parser) { 37 Ok(Some(definition)) => definitions.push(definition), 38 Ok(None) => break, 39 Err(..) => Document::synchronize(parser), 40 } 41 } 42 43 if !parser.is_line_start { 44 #[cfg(feature = "lax")] 45 parser.warn(SyntaxError::new_spanless( 46 "the document does not end with a new-line character", 47 )); 48 49 #[cfg(not(feature = "lax"))] 50 parser.error(SyntaxError::new_spanless( 51 "no new line found at end of file", 52 )); 53 } 54 55 let span = match (&documentation, definitions.last()) { 56 (Some(doc), Some(def)) => doc.span().union(def.span()), 57 (Some(doc), None) => doc.span(), 58 (None, Some(def)) => definitions.first().unwrap().span().union(def.span()), 59 (None, None) => Span::default(), 60 }; 61 Self { 62 span, 63 documentation, 64 definitions, 65 } 66 } 67} 68 69#[cfg(test)] 70mod test { 71 use super::*; 72 73 test_parse!(document_empty: "" |parser| Document::parse(&mut parser) => Document { .. }); 74 test_parse!(document_empty_newline: "\n" |parser| Document::parse(&mut parser) => Document { .. }); 75 76 test_parse!(document_documented: "#! hello\n#! world" |parser| Document::parse(&mut parser) => Document { documentation: Some(_), .. }); 77 test_parse!(document_documented_with_def: "#! hello\n#! world\n\n## Hello\nfunc f x = x\n" |parser| Document::parse(&mut parser) => Document { documentation: Some(_), definitions: [_], .. }); 78 79 test_parse_error!(document_no_final_newline: "func f x = x" |parser| Document::parse(&mut parser) => "no new line found at end of file"); 80 81 test_parse!(document_multiple_defs: "func f x = x\nfunc f y = y\nfunc g x = x\n" |parser| Document::parse(&mut parser) => Document { definitions: [_, _, _,], .. }); 82 test_parse_error!(document_defs_no_newline: "func f x = x func f y = y\n" |parser| Document::parse(&mut parser) => "definitions must be separated by line breaks"); 83 84 test_parse!(document_module_empty: "type A {}\n" |parser| Document::parse(&mut parser) => Document { definitions: [_], .. }); 85 test_parse!(document_module_nested: "type A {\n type B { }\n}\n" |parser| Document::parse(&mut parser) => Document { definitions: [_], .. }); 86 87 test_parse_error!(document_module_no_end_newline: "type A {\n type B { }}\n" |parser| Document::parse(&mut parser) => "definition in type must end with a line break"); 88 test_parse_error!(document_module_no_start_newline: "type A {type B { }}\n" |parser| Document::parse(&mut parser) => "definitions must be separated by line breaks"); 89 90 #[test] 91 #[rustfmt::skip] 92 fn document_error_recovery() { 93 use crate::Parser; 94 use trilogy_scanner::Scanner; 95 let scanner = Scanner::new("func f = y\nfunc f x = x\n"); 96 let mut parser = Parser::new(scanner); 97 let Amble { content, .. } = Amble::parse(&mut parser); 98 assert_eq!(content.definitions.len(), 1, "expected one definition to succeed"); 99 assert_eq!(parser.errors.len(), 1, "expected one definition to fail"); 100 } 101}