Skip to content

Commit a88d73a

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

20 files changed

+285
-0
lines changed

examples/apg4b-ex26.rs

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

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)