1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#![feature(test, let_chains)]
#![warn(
clippy::wildcard_imports,
clippy::string_add,
clippy::string_add_assign,
clippy::manual_ok_or,
unused_lifetimes
)]
#![allow(unused)]
pub mod ast;
pub mod interpreter;
pub mod lexer;
use std::io::{self, BufRead, Read, Write};
use std::{env, fs};
use itertools::Itertools;
use rand::Rng;
use crate::ast::parser::AstParser;
use crate::ast::AstVisitor;
use crate::interpreter::{AstInterpreter, InternalFunction, Value};
use crate::lexer::Lexer;
fn main() {
let args = env::args().collect_vec();
if args.len() < 2 {
println!("Sloth programming language interpreter\n");
println!("Usage: sloth <file>");
return;
}
let source_path = &args[1];
let Ok(source) = fs::read_to_string(source_path) else {
println!("Error while reading '{source_path}'");
return;
};
let lexer = Lexer::new(&source);
let tokens = lexer.collect_vec();
let mut parser = AstParser::new(tokens);
let ast = parser.parse();
println!("--- Abstract Syntax Tree ---");
println!("{ast:#?}");
println!("--- Program Output ---");
let mut interpreter = AstInterpreter::default();
// Defining some builtin callables for our interpreter
interpreter.callables.insert(
"print".to_owned(),
Box::new(InternalFunction(&|args| {
use std::fmt::Write;
let mut buffer = String::new();
for arg in args {
write!(&mut buffer, "{}", arg);
}
let mut stdout = io::stdout();
stdout.lock().write_all(buffer.as_bytes());
stdout.flush();
Value::Nil
})),
);
interpreter.callables.insert(
"println".to_owned(),
Box::new(InternalFunction(&|args| {
use std::fmt::Write;
let mut buffer = String::new();
for arg in args {
write!(&mut buffer, "{}", arg);
}
writeln!(&mut buffer);
let mut stdout = io::stdout();
stdout.lock().write_all(buffer.as_bytes());
stdout.flush();
Value::Nil
})),
);
interpreter.callables.insert(
"readln".to_owned(),
Box::new(InternalFunction(&|args| {
let stdin = io::stdin();
let mut line = String::new();
stdin
.lock()
.read_line(&mut line)
.expect("Failed to read line from stdin");
line.pop();
Value::String(line)
})),
);
interpreter.callables.insert(
"random".to_owned(),
Box::new(InternalFunction(&|args| {
let result = match args {
[] => rand::thread_rng().gen_range(1..=100),
[Value::Number(max)] => rand::thread_rng().gen_range(0..=*max),
[Value::Number(min), Value::Number(max)] => {
rand::thread_rng().gen_range(*min..=*max)
}
_ => panic!("Invalid usage of 'random' function"),
};
Value::Number(result)
})),
);
interpreter.callables.insert(
"len".to_owned(),
Box::new(InternalFunction(&|args| {
let result = match &args[0] {
Value::String(value) => value.len() as i32,
_ => panic!("Invalid usage of 'len' function"),
};
Value::Number(result)
})),
);
interpreter.callables.insert(
"parse_int".to_owned(),
Box::new(InternalFunction(&|args| {
let result = match &args[0] {
Value::String(value) => value.parse::<i32>(),
_ => panic!("Invalid usage of 'parse_int' function"),
}
.expect("Provided string was not an intenger");
Value::Number(result)
})),
);
interpreter.interpret(&ast);
}
|