You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.9 KiB
Rust

// 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<Node, SyntaxError> {
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<Token, SyntaxError> {
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<Token, SyntaxError> {
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<T>(&self, name: String, val: NodeVal) -> Result<Node, T> {
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<Node, SyntaxError>;
fn next(&mut self) -> Option<Result<Node, SyntaxError>> {
if let Some(Ok(token)) = self.lexer.peek() {
if token.kind == TokenKind::EOF {
return None;
}
}
Some(self.parse_node())
}
}
// Copyright (C) 2021 Fefie <owo@fef.moe>
// 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 <https://git.pixie.town/thufie/CNPL>.
//
// gayconf comes with ABSOLUTELY NO WARRANTY, to the extent
// permitted by applicable law. See the CNPL for details.