Skip to content

Commit b96ed02

Browse files
committed
First commit. Basic stuff is working
1 parent 5f65316 commit b96ed02

File tree

3 files changed

+268
-1
lines changed

3 files changed

+268
-1
lines changed

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ Cargo.lock
1818
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
1919
# and can be added to the global gitignore or merged into this file. For a more nuclear
2020
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
21-
#.idea/
21+
#.idea/
22+
23+
# Added by cargo
24+
25+
/target

Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "plenty"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]

src/main.rs

+257
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
use std::io::Write;
2+
use std::collections::HashMap;
3+
use std::error::Error;
4+
5+
#[derive(Debug, Clone)]
6+
enum Token {
7+
Display,
8+
NumberI32(i32),
9+
NumberI64(i64),
10+
Text(String),
11+
MakeArrayNumberI32,
12+
MakeArrayText,
13+
ArrayNumberI32(Vec<i32>),
14+
ArrayText(Vec<String>),
15+
Join,
16+
Plus,
17+
Minus,
18+
Multiply,
19+
Divide,
20+
LParen,
21+
RParen,
22+
Open,
23+
ReadLines,
24+
Clear,
25+
ListDir,
26+
}
27+
28+
impl std::str::FromStr for Token {
29+
type Err = &'static str;
30+
31+
fn from_str(s: &str) -> Result<Self, Self::Err> {
32+
match s {
33+
"." => Ok(Token::Display),
34+
"+" => Ok(Token::Plus),
35+
"-" => Ok(Token::Minus),
36+
"*" => Ok(Token::Multiply),
37+
"/" => Ok(Token::Divide),
38+
"(" => Ok(Token::LParen),
39+
")" => Ok(Token::RParen),
40+
41+
"open" => Ok(Token::Open),
42+
"readlines" => Ok(Token::ReadLines),
43+
"clear" => Ok(Token::Clear),
44+
"listdir" => Ok(Token::ListDir),
45+
46+
"arrnum" => Ok(Token::MakeArrayNumberI32),
47+
"arrtxt" => Ok(Token::MakeArrayText),
48+
"join" => Ok(Token::Join),
49+
_ => {
50+
if let Ok(number) = s.parse::<i32>() {
51+
Ok(Token::NumberI32(number))
52+
} else {
53+
Ok(Token::Text(s.to_string()))
54+
}
55+
}
56+
}
57+
}
58+
}
59+
60+
struct Stack {
61+
items: Vec<Token>,
62+
}
63+
64+
impl Stack {
65+
fn new() -> Stack {
66+
Stack {
67+
items: vec![],
68+
}
69+
}
70+
71+
fn clear(&mut self) {
72+
self.items.clear();
73+
}
74+
75+
fn display(&self) {
76+
println!("{:?}", self.items);
77+
}
78+
79+
fn push_str(&mut self, item: &str) -> Result<(), Box<dyn Error>> {
80+
match item.parse::<Token>() {
81+
Ok(token) => {
82+
self.push(token)?;
83+
},
84+
Err(_) => {
85+
self.push(Token::Text(item.to_string()))?;
86+
}
87+
}
88+
Ok(())
89+
}
90+
91+
fn push(&mut self, item: Token) -> Result<(), Box<dyn Error>> {
92+
match item {
93+
Token::Display => self.display(),
94+
Token::Plus => self.add()?,
95+
Token::Clear => self.clear(),
96+
Token::NumberI32(_) => self.items.push(item),
97+
Token::NumberI64(_) => self.items.push(item),
98+
Token::Text(_) => self.items.push(item),
99+
Token::Minus => todo!(),
100+
Token::Multiply => self.multiply()?,
101+
Token::Divide => todo!(),
102+
Token::LParen => todo!(),
103+
Token::RParen => todo!(),
104+
Token::Open => todo!(),
105+
Token::ReadLines => todo!(),
106+
Token::ListDir => self.list_dir()?,
107+
Token::MakeArrayNumberI32 => self.array_number_i32()?,
108+
Token::MakeArrayText => self.array_text()?,
109+
Token::ArrayNumberI32(_) => self.items.push(item),
110+
Token::ArrayText(_) => self.items.push(item),
111+
Token::Join => self.join()?,
112+
}
113+
Ok(())
114+
}
115+
116+
fn join(&mut self) -> Result<(), Box<dyn Error>> {
117+
if let Some(Token::ArrayText(items)) = self.pop() {
118+
let total = items.join("");
119+
self.push(Token::Text(total))?;
120+
} else {
121+
return Err("Expected an array of text".into());
122+
}
123+
Ok(())
124+
}
125+
126+
fn array_number_i32(&mut self) -> Result<(), Box<dyn Error>> {
127+
let mut items = vec![];
128+
let count = match self.pop() {
129+
Some(Token::NumberI32(count)) => count,
130+
_ => return Err("Expected a number".into()),
131+
};
132+
133+
for _ in 0..count {
134+
if let Some(Token::NumberI32(item)) = self.pop() {
135+
items.push(item);
136+
}
137+
}
138+
139+
self.push(Token::ArrayNumberI32(items))?;
140+
Ok(())
141+
}
142+
143+
fn array_text(&mut self) -> Result<(), Box<dyn Error>> {
144+
let mut items = vec![];
145+
let count = match self.pop() {
146+
Some(Token::NumberI32(count)) => count,
147+
_ => return Err("Expected a number".into()),
148+
};
149+
150+
for _ in 0..count {
151+
if let Some(Token::Text(item)) = self.pop() {
152+
items.push(item);
153+
}
154+
}
155+
156+
self.push(Token::ArrayText(items))?;
157+
Ok(())
158+
}
159+
160+
161+
fn list_dir(&self) -> Result<(), Box<dyn Error>> {
162+
let dir = std::fs::read_dir(".")?;
163+
for entry in dir {
164+
let entry = entry?;
165+
let path = entry.path();
166+
let path_str = path.to_str().unwrap();
167+
println!("{}", path_str);
168+
}
169+
Ok(())
170+
}
171+
172+
fn add(&mut self) -> Result<(), Box<dyn Error>> {
173+
if self.items.len() < 2 {
174+
return Ok(());
175+
}
176+
177+
let token_a = self.pop().unwrap();
178+
let token_b = self.pop().unwrap();
179+
match (&token_a, &token_b) {
180+
(Token::NumberI32(a), Token::NumberI32(b)) => {
181+
self.push(Token::NumberI32(a + b))?;
182+
},
183+
(Token::Text(a), Token::Text(b)) => {
184+
self.push(Token::Text(format!("{}{}", a, b)))?;
185+
},
186+
_ => {
187+
return Err(format!("Cannot add {:?} to {:?}", &token_a, &token_b).into());
188+
}
189+
}
190+
Ok(())
191+
}
192+
193+
fn multiply(&mut self) -> Result<(), Box<dyn Error>> {
194+
if self.items.len() < 2 {
195+
return Ok(());
196+
}
197+
198+
if let Some(Token::NumberI32(b)) = self.pop() {
199+
if let Some(Token::NumberI32(a)) = self.pop() {
200+
self.push(Token::NumberI32(a * b))?;
201+
} else {
202+
return Err("Expected a number".into());
203+
}
204+
Ok(())
205+
} else {
206+
Err("Expected a number".into())
207+
}
208+
}
209+
210+
fn pop(&mut self) -> Option<Token> {
211+
self.items.pop()
212+
}
213+
}
214+
215+
216+
fn main() {
217+
let banner = r#"
218+
::::::::: ::: :::::::::: :::: ::: ::::::::::: ::: :::
219+
:+: :+: :+: :+: :+:+: :+: :+: :+: :+:
220+
+:+ +:+ +:+ +:+ :+:+:+ +:+ +:+ +:+ +:+
221+
+#++:++#+ +#+ +#++:++# +#+ +:+ +#+ +#+ +#++:
222+
+#+ +#+ +#+ +#+ +#+#+# +#+ +#+
223+
#+# #+# #+# #+# #+#+# #+# #+#
224+
### ########## ########## ### #### ### ###
225+
"#;
226+
println!("{}", banner);
227+
228+
let mut stack = Stack::new();
229+
230+
// Let's make an interpreter loop
231+
let prompt = "---> ";
232+
let mut input = String::new();
233+
loop {
234+
print!("{}", prompt);
235+
std::io::stdout().flush().unwrap();
236+
237+
input.clear();
238+
std::io::stdin().read_line(&mut input).unwrap();
239+
input.shrink_to_fit();
240+
let input_clean = &input[..input.len()-1].trim();
241+
242+
if ["exit", "q", "quit"].contains(input_clean) {
243+
break;
244+
}
245+
246+
let items: Vec<&str> = input_clean.split_whitespace().collect();
247+
for item in items {
248+
match stack.push_str(item) {
249+
Ok(_) => {},
250+
Err(e) => {
251+
eprintln!("Error: {}", e);
252+
break;
253+
}
254+
}
255+
}
256+
}
257+
}

0 commit comments

Comments
 (0)