Skip to content

Commit 4551db2

Browse files
committed
Add a test for APG4b-EX26
1 parent 9b3b5e9 commit 4551db2

20 files changed

+287
-0
lines changed

examples/apg4b-ex26.rs

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// https://atcoder.jp/contests/APG4b/tasks/APG4b_bw
2+
3+
use itertools::Itertools as _;
4+
use maplit::hashmap;
5+
use matches::matches;
6+
7+
use std::collections::HashMap;
8+
use std::io::{self, Read as _};
9+
use std::str::FromStr;
10+
11+
fn main() {
12+
let mut input = "".to_owned();
13+
io::stdin().read_to_string(&mut input).unwrap();
14+
let mut env = hashmap!();
15+
for line in input.lines().skip(1) {
16+
line.parse::<Stmt>().unwrap().eval(&mut env);
17+
}
18+
}
19+
20+
#[derive(Debug)]
21+
enum Stmt {
22+
DeclInt(char, IntExpr),
23+
PrintInt(IntExpr),
24+
DeclVec(char, VecExpr),
25+
PrintVec(VecExpr),
26+
}
27+
28+
impl Stmt {
29+
fn eval(&self, env: &mut HashMap<char, Val>) {
30+
match self {
31+
Self::DeclInt(name, expr) => {
32+
env.insert(*name, Val::Int(expr.eval(env)));
33+
}
34+
Self::PrintInt(expr) => println!("{}", expr.eval(env)),
35+
Self::DeclVec(name, expr) => {
36+
env.insert(*name, Val::Vec(expr.eval(env)));
37+
}
38+
Self::PrintVec(expr) => println!("[ {} ]", expr.eval(env).iter().format(" ")),
39+
}
40+
}
41+
}
42+
43+
impl FromStr for Stmt {
44+
type Err = (String, usize, nom::error::ErrorKind);
45+
46+
fn from_str(input: &str) -> Result<Self, (String, usize, nom::error::ErrorKind)> {
47+
use nom::branch::alt;
48+
use nom::bytes::complete::{tag, take_while_m_n};
49+
use nom::character::complete::{char, one_of, space0, space1};
50+
use nom::combinator::{map, map_res};
51+
use nom::multi::{fold_many0, separated_list};
52+
use nom::sequence::{pair, preceded, tuple};
53+
use nom::IResult;
54+
55+
fn decl_int(input: &str) -> IResult<&str, Stmt> {
56+
let (input, _) = space0(input)?;
57+
let (input, _) = tag("int")(input)?;
58+
let (input, _) = space1(input)?;
59+
let (input, name) = var_name(input)?;
60+
let (input, _) = space0(input)?;
61+
let (input, _) = tag("=")(input)?;
62+
let (input, _) = space0(input)?;
63+
let (input, expr) = int_expr(input)?;
64+
let (input, _) = space0(input)?;
65+
let (input, _) = char(';')(input)?;
66+
Ok((input, Stmt::DeclInt(name, expr)))
67+
}
68+
69+
fn print_int(input: &str) -> IResult<&str, Stmt> {
70+
let (input, _) = space0(input)?;
71+
let (input, _) = tag("print_int")(input)?;
72+
let (input, _) = space1(input)?;
73+
let (input, expr) = int_expr(input)?;
74+
let (input, _) = space0(input)?;
75+
let (input, _) = tag(";")(input)?;
76+
Ok((input, Stmt::PrintInt(expr)))
77+
}
78+
79+
fn decl_vec(input: &str) -> IResult<&str, Stmt> {
80+
let (input, _) = space0(input)?;
81+
let (input, _) = tag("vec")(input)?;
82+
let (input, _) = space1(input)?;
83+
let (input, name) = var_name(input)?;
84+
let (input, _) = space0(input)?;
85+
let (input, _) = char('=')(input)?;
86+
let (input, _) = space0(input)?;
87+
let (input, val) = vec_expr(input)?;
88+
let (input, _) = space0(input)?;
89+
let (input, _) = char(';')(input)?;
90+
Ok((input, Stmt::DeclVec(name, val)))
91+
}
92+
93+
fn print_vec(input: &str) -> IResult<&str, Stmt> {
94+
let (input, _) = space0(input)?;
95+
let (input, _) = tag("print_vec")(input)?;
96+
let (input, _) = space1(input)?;
97+
let (input, val) = vec_expr(input)?;
98+
let (input, _) = space0(input)?;
99+
let (input, _) = char(';')(input)?;
100+
Ok((input, Stmt::PrintVec(val)))
101+
}
102+
103+
fn int_expr(input: &str) -> IResult<&str, IntExpr> {
104+
let (input, expr) = int_term(input)?;
105+
fold_many0(
106+
preceded(space0, pair(one_of("+-"), preceded(space0, int_term))),
107+
expr,
108+
|expr, (op, term)| match op {
109+
'+' => IntExpr::Add(Box::new(expr), Box::new(term)),
110+
'-' => IntExpr::Sub(Box::new(expr), Box::new(term)),
111+
_ => unreachable!(),
112+
},
113+
)(input)
114+
}
115+
116+
fn int_term(input: &str) -> IResult<&str, IntExpr> {
117+
let (input, _) = space0(input)?;
118+
alt((
119+
map(var_name, IntExpr::Var),
120+
map(
121+
take_while_m_n::<_, &str, _>(1, 1, |c| matches!(c, '0'..='9')),
122+
|s| IntExpr::Lit(s.parse().unwrap()),
123+
),
124+
))(input)
125+
}
126+
127+
fn vec_expr(input: &str) -> IResult<&str, VecExpr> {
128+
let (input, expr) = vec_term(input)?;
129+
fold_many0(
130+
preceded(space0, pair(one_of("+-"), preceded(space0, vec_term))),
131+
expr,
132+
|expr, (op, term)| match op {
133+
'+' => VecExpr::Add(Box::new(expr), Box::new(term)),
134+
'-' => VecExpr::Sub(Box::new(expr), Box::new(term)),
135+
_ => unreachable!(),
136+
},
137+
)(input)
138+
}
139+
140+
fn vec_term(input: &str) -> IResult<&str, VecExpr> {
141+
let (input, _) = space0(input)?;
142+
alt((map(var_name, VecExpr::Var), |input| {
143+
let (input, _) = char('[')(input)?;
144+
let (input, _) = space0(input)?;
145+
let (input, vec) =
146+
separated_list(tuple((space0, char(','), space0)), int_expr)(input)?;
147+
let (input, _) = space0(input)?;
148+
let (input, _) = char(']')(input)?;
149+
Ok((input, VecExpr::Lit(vec)))
150+
}))(input)
151+
}
152+
153+
fn var_name(input: &str) -> IResult<&str, char> {
154+
map_res(take_while_m_n(1, 1, |c| matches!(c, 'a'..='z')), str::parse)(input)
155+
}
156+
157+
decl_int(input)
158+
.or_else(|_| print_int(input))
159+
.or_else(|_| decl_vec(input))
160+
.or_else(|_| print_vec(input))
161+
.map(|(_, stmt)| stmt)
162+
.map_err(|err| match err {
163+
nom::Err::Incomplete(_) => unreachable!(),
164+
nom::Err::Error((s, k)) | nom::Err::Failure((s, k)) => {
165+
(input.to_owned(), input.len() - s.len(), k)
166+
}
167+
})
168+
}
169+
}
170+
171+
#[derive(Debug)]
172+
enum Val {
173+
Int(i32),
174+
Vec(Vec<i32>),
175+
}
176+
177+
impl Val {
178+
fn unwrap_int(&self) -> i32 {
179+
match self {
180+
Self::Int(n) => *n,
181+
Self::Vec(_) => panic!(),
182+
}
183+
}
184+
185+
fn unwrap_vec(&self) -> &[i32] {
186+
match self {
187+
Self::Int(_) => panic!(),
188+
Self::Vec(vec) => vec,
189+
}
190+
}
191+
}
192+
193+
#[derive(Debug, Clone)]
194+
enum IntExpr {
195+
Lit(i32),
196+
Var(char),
197+
Add(Box<Self>, Box<Self>),
198+
Sub(Box<Self>, Box<Self>),
199+
}
200+
201+
impl IntExpr {
202+
fn eval(&self, env: &HashMap<char, Val>) -> i32 {
203+
match self {
204+
Self::Lit(n) => *n,
205+
Self::Var(s) => env[s].unwrap_int(),
206+
Self::Add(l, r) => l.eval(env) + r.eval(env),
207+
Self::Sub(l, r) => l.eval(env) - r.eval(env),
208+
}
209+
}
210+
}
211+
212+
#[derive(Debug, Clone)]
213+
enum VecExpr {
214+
Lit(Vec<IntExpr>),
215+
Var(char),
216+
Add(Box<Self>, Box<Self>),
217+
Sub(Box<Self>, Box<Self>),
218+
}
219+
220+
impl VecExpr {
221+
fn eval(&self, env: &HashMap<char, Val>) -> Vec<i32> {
222+
match self {
223+
Self::Lit(v) => v.iter().map(|x| x.eval(env)).collect(),
224+
Self::Var(s) => env[s].unwrap_vec().to_owned(),
225+
Self::Add(l, r) => {
226+
let (l, r) = (l.eval(env), r.eval(env));
227+
l.into_iter().zip_eq(r).map(|(l, r)| l + r).collect()
228+
}
229+
Self::Sub(l, r) => {
230+
let (l, r) = (l.eval(env), r.eval(env));
231+
l.into_iter().zip_eq(r).map(|(l, r)| l - r).collect()
232+
}
233+
}
234+
}
235+
}

examples/tests.ron

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
name: "APG4b: EX25 - 集合の操作 / 3.05",
1212
matching: ExactWords,
1313
),
14+
"apg4b-ex26": (
15+
name: "APG4b: EX26 - 電卓を作ろう3 / 3.06",
16+
matching: ExactWords,
17+
),
1418
"practice-a": (
1519
name: "practice contest: A - Welcome to AtCoder",
1620
matching: ExactWords,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
4
2+
int x = 1 + 2 ;
3+
print_int x + 3 ;
4+
vec a = [ 1 , 2 , x ] ;
5+
print_vec a + [ 4 , 5 , 6 ] ;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2
2+
print_int 1 - 2 ;
3+
print_vec [ 1 , 2 , 3 ] - [ 3 , 2 , 1 ] ;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
1
2+
print_int 5 ;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
1
2+
print_vec [ 1 , 2 ] ;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2
2+
int x = 1 ;
3+
print_int x ;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2
2+
vec a = [ 3 , 4 ] ;
3+
print_vec a ;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
4
2+
int x = 1 ;
3+
int y = 2 ;
4+
int z = 3 ;
5+
print_int x + y + z ;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
4
2+
vec a = [ 1 , 2 , 3 ] ;
3+
vec b = [ 4 , 5 , 6 ] ;
4+
vec c = [ 7 , 8 , 9 ] ;
5+
print_vec a + b + c ;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
6
2+
vec a = [ 1 , 2 ] ;
3+
vec b = a + [ 3 , 4 ] ;
4+
vec c = a - [ 5 , 6 ] ;
5+
print_vec a ;
6+
print_vec b ;
7+
print_vec c ;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
6
2+
[ 5 7 9 ]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-1
2+
[ -2 0 2 ]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
5
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ 1 2 ]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ 3 4 ]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
6
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ 12 15 18 ]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[ 1 2 ]
2+
[ 4 6 ]
3+
[ -4 -4 ]

0 commit comments

Comments
 (0)