Skip to content

Commit

Permalink
feat: implement parser (1) (#2)
Browse files Browse the repository at this point in the history
* feat: implement boolean tokenizer

* feat: implement string parser

* feat: implement unary operator tokenizer

* feat: implement binary operator tokenizer

* feat: implement if operator tokenizer

* refactor: move decrypt process to tokenizer

* feat: implement stringifier

* feat: implement unary, binary parser
  • Loading branch information
sor4chi authored Jun 28, 2024
1 parent 404d766 commit 20761b3
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 20 deletions.
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"files.associations": {
".fantomasignore": "ignore",
"*.html": "html",
"*.blade.php": "html",
"*.tsx": "typescriptreact",
"*.bnf": "ebnf",
"*.txt": "plaintext",
"*.ts": "typescript",
"あ": "plaintext",
"ostream": "cpp"
}
}
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
dotenv = "0.15.0"
proconio = "0.4.5"
reqwest = { version = "0.12.5", features = ["json"] }
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.118"
Expand Down
14 changes: 14 additions & 0 deletions src/bin/stringify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use icfpc2024::tokenizer::Tokenizer;
use proconio::input;

fn main() {
input! {
text: String,
}
let mut tokenizer = Tokenizer::new(&text);
let result = tokenizer.tokenize();

for token in result {
println!("{:?}", token);
}
}
145 changes: 132 additions & 13 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,145 @@
use crate::tokenizer::Token;

const INTEGER_ASCII: &str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
#[derive(Debug, PartialEq)]
enum Node {
IntegerLiteral(usize),
StringLiteral(String),
UnaryOperator((String, Box<Node>)),
BinaryOperator((String, Box<Node>, Box<Node>)),
}

pub struct Parser<'a> {
tokens: &'a [Token],
position: usize,
}

impl<'a> Parser<'a> {
pub fn new(tokens: &'a [Token]) -> Self {
Self {
tokens,
position: 0,
}
}

pub fn parse(&mut self) -> Node {
self.parse_node()
}

fn parse_node(&mut self) -> Node {
match self.tokens[self.position] {
Token::Integer(value) => {
self.position += 1;
Node::IntegerLiteral(value)
}
Token::String(ref value) => {
self.position += 1;
Node::StringLiteral(value.clone())
}
Token::UnaryOperator(_) => self.parse_unary(),
Token::BinaryOperator(_) => self.parse_binary(),
_ => panic!("Expected integer or unary operator"),
}
}

fn parse_unary(&mut self) -> Node {
let operator = match self.tokens[self.position] {
Token::UnaryOperator(ref operator) => operator.clone(),
_ => panic!("Expected unary operator"),
};
self.position += 1;
let operand = Box::new(self.parse_node());
Node::UnaryOperator((operator, operand))
}

fn parse_integer(indicator: Token) -> usize {
assert!(matches!(indicator, Token::Integer(_)));
let mut result = 0;
for c in indicator.to_string().chars() {
let index = INTEGER_ASCII.find(c).unwrap();
result = result * INTEGER_ASCII.len() + index;
fn parse_binary(&mut self) -> Node {
let operator = match self.tokens[self.position] {
Token::BinaryOperator(ref operator) => operator.clone(),
_ => panic!("Expected binary operator"),
};
self.position += 1;
let left = Box::new(self.parse_node());
let right = Box::new(self.parse_node());
Node::BinaryOperator((operator, left, right))
}
result
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_parse_integer() {
assert_eq!(INTEGER_ASCII.len(), 94);
let input = Token::Integer("/6".to_string());
let expected = 1337;
assert_eq!(parse_integer(input), expected);
fn test_parse_unary() {
let tokens = vec![Token::UnaryOperator("-".to_string()), Token::Integer(3)];
let mut parser = Parser::new(&tokens);
let node = parser.parse_unary();
assert_eq!(
node,
Node::UnaryOperator(("-".to_string(), Box::new(Node::IntegerLiteral(3))))
);
}

#[test]
fn test_parse_nested_unary() {
let tokens = vec![
Token::UnaryOperator("-".to_string()),
Token::UnaryOperator("-".to_string()),
Token::Integer(3),
];
let mut parser = Parser::new(&tokens);
let node = parser.parse_unary();
assert_eq!(
node,
Node::UnaryOperator((
"-".to_string(),
Box::new(Node::UnaryOperator((
"-".to_string(),
Box::new(Node::IntegerLiteral(3))
)))
))
);
}

#[test]
fn test_parse_binary() {
let tokens = vec![
Token::BinaryOperator("+".to_string()),
Token::Integer(3),
Token::Integer(4),
];
let mut parser = Parser::new(&tokens);
let node = parser.parse_binary();
assert_eq!(
node,
Node::BinaryOperator((
"+".to_string(),
Box::new(Node::IntegerLiteral(3)),
Box::new(Node::IntegerLiteral(4))
))
);
}

#[test]
fn test_parse_nested_binary() {
let tokens = vec![
Token::BinaryOperator("+".to_string()),
Token::Integer(3),
Token::BinaryOperator("+".to_string()),
Token::Integer(4),
Token::Integer(5),
];
let mut parser = Parser::new(&tokens);
let node = parser.parse_binary();
assert_eq!(
node,
Node::BinaryOperator((
"+".to_string(),
Box::new(Node::IntegerLiteral(3)),
Box::new(Node::BinaryOperator((
"+".to_string(),
Box::new(Node::IntegerLiteral(4)),
Box::new(Node::IntegerLiteral(5))
)))
))
);
}
}
Loading

0 comments on commit 20761b3

Please sign in to comment.