yash_syntax/
parser.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2020 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Syntax parser for the shell language.
18//!
19//! The shell language parsing system has two important components: the lexical
20//! analyzer and the syntax parser.
21//!
22//! The lexical analyzer, or simply [lexer](lex::Lexer), extracts tokens from
23//! the source code string. Tokenization for the shell language involves parsing
24//! expansions like parameter expansions and command substitutions, which makes
25//! the lexer much more complicated than those for normal programming languages.
26//! However, as long as you use the lexer indirectly via the parser, you don't
27//! have to care about such details.
28//!
29//! The syntax [parser](Parser) examines tokens produced by the lexer and
30//! constructs abstract syntax trees. The below code illustrates the basic usage
31//! of the parser.
32//!
33//! ```
34//! // First, prepare an input object that the lexer reads from.
35//! use yash_syntax::input::Memory;
36//! use yash_syntax::source::Source;
37//! # // TODO demonstrate with a Source other than Unknown
38//! let input = Box::new(Memory::new("echo $?"));
39//!
40//! // Next, create a lexer.
41//! use std::num::NonZeroU64;
42//! use yash_syntax::parser::lex::Lexer;
43//! let line = NonZeroU64::new(1).unwrap();
44//! let mut lexer = Lexer::new(input, line, Source::Unknown.into());
45//!
46//! // Then, create a new parser borrowing the lexer.
47//! use yash_syntax::parser::Parser;
48//! use yash_syntax::alias::EmptyGlossary;
49//! let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
50//!
51//! // Lastly, call the parser's function to get an AST.
52//! use futures_executor::block_on;
53//! let list = block_on(parser.command_line()).unwrap().unwrap();
54//! assert_eq!(list.to_string(), "echo $?");
55//! ```
56//!
57//! If there is any error reading the input or analyzing the source code, the
58//! parser returns an [`Error`] object. In case of a syntax error, the `Error`
59//! object's [cause](ErrorCause) will be a value of [`SyntaxError`] that
60//! describes it.
61//!
62//! Most lexer and parser functions are asynchronous because underlying
63//! [input](crate::input::Input) is asynchronous. Only as many lines are read
64//! from the input as needed to parse a complete AST.
65//!
66//! Note that most AST types have the [`FromStr`](std::str::FromStr) trait
67//! implemented for them. If you don't need to include source location
68//! information in the resultant AST, calling the `parse` function on a string
69//! is a convenient way to parse a code fragment.
70//! See the [`syntax`](crate::syntax) module for an example of this.
71
72mod core;
73mod error;
74mod from_str;
75
76mod and_or;
77mod case;
78mod command;
79mod compound_command;
80mod for_loop;
81mod function;
82mod grouping;
83mod r#if;
84mod list;
85mod pipeline;
86mod redir;
87mod simple_command;
88mod while_loop;
89
90pub mod lex;
91
92pub use self::core::Parser;
93pub use self::core::Rec;
94pub use self::core::Result;
95pub use self::error::Error;
96pub use self::error::ErrorCause;
97pub use self::error::SyntaxError;