// See the end of this file for copyright and license terms. use crate::lex::{Lexer, SyntaxError, Token, TokenKind}; use crate::{Node, NodeVal}; pub struct Parser<'a> { lexer: Lexer<'a>, } impl<'a> Parser<'a> { pub const fn new(lexer: Lexer<'a>) -> Parser<'a> { Parser { lexer } } fn parse_node(&mut self) -> Result { let ident = self.require_kind(TokenKind::Ident)?; self.require_kind(TokenKind::Eq)?; let val = self.require_next()?; let node = match val.kind { TokenKind::TrueKeyword => self.node_result(ident.raw, NodeVal::Bool(true)), TokenKind::FalseKeyword => self.node_result(ident.raw, NodeVal::Bool(false)), TokenKind::IntLiteral => self.node_result( ident.raw, NodeVal::Int(val.raw.parse().expect("This shouldn't be possible lol")), ), TokenKind::StringLiteral => self.node_result(ident.raw, NodeVal::String(val.raw)), _ => self.lexer.syntax_error(String::from("Expected a value")), }?; self.require_kind(TokenKind::Semi)?; Ok(node) } fn require_kind(&mut self, kind: TokenKind) -> Result { if let Some(res) = self.lexer.next() { if let Ok(tok) = res { if tok.kind == kind { Ok(tok) } else { self.lexer.syntax_error(format!("Expected {:?}, got {:?}", kind, tok.kind)) } } else { res } } else { self.lexer.syntax_error(String::from("Unexpected EOF")) } } fn require_next(&mut self) -> Result { match self.lexer.next() { Some(result) => result, None => self .lexer .syntax_error(String::from("Unexpected end of file")), } } #[allow(clippy::unnecessary_wraps)] // Convenience wrapper fn node_result(&self, name: String, val: NodeVal) -> Result { Ok(self.make_node(name, val)) } fn make_node(&self, name: String, val: NodeVal) -> Node { Node { name, val } } } impl<'a> Iterator for Parser<'a> { type Item = Result; fn next(&mut self) -> Option> { if let Some(Ok(token)) = self.lexer.peek() { if token.kind == TokenKind::EOF { return None; } } Some(self.parse_node()) } } // Copyright (C) 2021 Fefie // This file is part of gayconf. // // gayconf is non-violent software: you can use, redistribute, // and/or modify it under the terms of the CNPLv6+ as found // in the LICENSE file in the source code root directory or // at . // // gayconf comes with ABSOLUTELY NO WARRANTY, to the extent // permitted by applicable law. See the CNPL for details.