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 ;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy