Skip to content

Commit 8a60984

Browse files
committed
Add a test for APG4b-EX26
1 parent f4c96aa commit 8a60984

20 files changed

+302
-0
lines changed

examples/apg4b-ex26.rs

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

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)