Browse Source

MVP interpreter

master
Stephen 5 months ago
parent
commit
689a22a647
3 changed files with 391 additions and 39 deletions
  1. +131
    -37
      Cargo.lock
  2. +3
    -0
      Cargo.toml
  3. +257
    -2
      src/main.rs

+ 131
- 37
Cargo.lock View File

@ -7,14 +7,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "async-trait"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -89,10 +95,12 @@ name = "cat-disruptor-6500"
version = "0.1.0"
dependencies = [
"phf",
"png",
"serde",
"serenity",
"tokio",
"toml",
"xbasic",
]
[[package]]
@ -143,6 +151,16 @@ dependencies = [
]
[[package]]
name = "deflate"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
dependencies = [
"adler32",
"byteorder",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@ -175,7 +193,7 @@ dependencies = [
"cfg-if 0.1.10",
"crc32fast",
"libc",
"miniz_oxide",
"miniz_oxide 0.4.3",
]
[[package]]
@ -243,9 +261,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -533,6 +551,15 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
@ -617,6 +644,17 @@ dependencies = [
]
[[package]]
name = "num-derive"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
@ -693,9 +731,9 @@ dependencies = [
"phf_generator",
"phf_shared",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -731,9 +769,9 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -742,9 +780,9 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -760,6 +798,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "png"
version = "0.16.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfe7f9f1c730833200b134370e1d5098964231af8450bce9b78ee3ab5278b970"
dependencies = [
"bitflags",
"crc32fast",
"deflate",
"miniz_oxide 0.3.7",
]
[[package]]
name = "ppv-lite86"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@ -779,11 +829,29 @@ checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid 0.1.0",
]
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
"unicode-xid 0.2.1",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
]
[[package]]
@ -792,7 +860,7 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
"proc-macro2 1.0.24",
]
[[package]]
@ -948,9 +1016,9 @@ version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -1061,13 +1129,24 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid 0.1.0",
]
[[package]]
name = "syn"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2 1.0.24",
"quote 1.0.7",
"unicode-xid 0.2.1",
]
[[package]]
@ -1117,9 +1196,9 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -1182,9 +1261,9 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
]
[[package]]
@ -1272,6 +1351,12 @@ dependencies = [
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
@ -1348,9 +1433,9 @@ dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
"wasm-bindgen-shared",
]
@ -1372,7 +1457,7 @@ version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
dependencies = [
"quote",
"quote 1.0.7",
"wasm-bindgen-macro-support",
]
@ -1382,9 +1467,9 @@ version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.48",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1485,3 +1570,12 @@ dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "xbasic"
version = "0.2.0"
dependencies = [
"num-derive",
"num-traits",
"phf",
]

+ 3
- 0
Cargo.toml View File

@ -12,3 +12,6 @@ tokio = {version = "0.2", features = ["full", "time"] }
phf = { version = "0.8", features = ["macros"] }
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
# xbasic = "0.2"
xbasic = { path = "../xbasic", version = "0.2.0" }
png = "0.16"

+ 257
- 2
src/main.rs View File

@ -2,13 +2,125 @@ mod config;
use phf::phf_map;
use serenity::async_trait;
use serenity::http::AttachmentType;
use serenity::model::channel::{Message, ReactionType};
use serenity::model::id::UserId;
use serenity::model::prelude::Ready;
use serenity::prelude::*;
use serenity::Client;
use std::borrow::Cow;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use xbasic::basic_io::BasicIO;
use xbasic::expr::ExprValue;
use xbasic::xbasic::XBasicBuilder;
struct Handler;
#[derive(Clone)]
struct FrameBuffer {
width: u32,
height: u32,
buffer: Vec<u8>,
}
impl FrameBuffer {
fn new(width: u32, height: u32) -> Self {
Self {
width,
height,
buffer: vec![0; width as usize * height as usize * 4],
}
}
fn set_pixel(&mut self, x: u32, y: u32, red: u8, green: u8, blue: u8, alpha: u8) {
if x >= self.width || y >= self.height {
return;
}
let x = x as usize;
let y = y as usize;
self.buffer[(x + self.width as usize * y) * 4] = red;
self.buffer[(x + self.width as usize * y) * 4 + 1] = green;
self.buffer[(x + self.width as usize * y) * 4 + 2] = blue;
self.buffer[(x + self.width as usize * y) * 4 + 3] = alpha;
}
fn as_png_vec(&self) -> Vec<u8> {
let mut buffer: Vec<u8> = Vec::new();
{
let mut encoder = png::Encoder::new(&mut buffer, self.width, self.height);
encoder.set_color(png::ColorType::RGBA);
encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header().unwrap();
writer.write_image_data(&self.buffer).unwrap();
}
buffer
}
}
struct DiscordIO {
s: String,
frame: Option<FrameBuffer>,
}
impl DiscordIO {
fn new() -> Self {
Self {
s: String::new(),
frame: None,
}
}
}
impl BasicIO for DiscordIO {
fn read_line(&mut self) -> String {
unimplemented!()
}
fn write_line(&mut self, line: String) {
self.s += &*(line + "\r\n");
}
}
struct Program {
code: HashMap<u32, String>,
}
impl Program {
fn new() -> Self {
Self {
code: HashMap::new(),
}
}
fn stringify(&self) -> String {
let mut code: Vec<(u32, String)> =
self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect();
code.sort_by(|a, b| a.0.cmp(&b.0));
code.into_iter()
.map(|a| a.1)
.collect::<Vec<String>>()
.join("\n")
}
fn stringy_line_nums(&self) -> String {
let mut code: Vec<(u32, String)> =
self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect();
code.sort_by(|a, b| a.0.cmp(&b.0));
code.into_iter()
.map(|a| format!("{}\t{}", a.0, a.1))
.collect::<Vec<String>>()
.join("\n")
}
}
struct Handler {
programs: Arc<Mutex<HashMap<UserId, Program>>>,
}
static EMOJI_MAP: phf::Map<&'static str, &'static str> = phf_map! {
"cat" => "🐈",
@ -41,6 +153,147 @@ impl EventHandler for Handler {
}
}
}
for line in msg.content.split('\n') {
if self.programs.lock().await.contains_key(&msg.author.id) {
match line {
"!STOP" => {
self.programs.lock().await.remove(&msg.author.id).unwrap();
}
"RUN" => {
let code = self.programs.lock().await[&msg.author.id].stringify();
let io = DiscordIO::new();
let (output, fb, errors) = {
let mut xbb = XBasicBuilder::new(io);
xbb.compute_limit(1000000000);
xbb.define_function("setframe".to_owned(), 2, |args, io| {
let w = args[0].clone().into_decimal() as u32;
let h = args[1].clone().into_decimal() as u32;
io.frame = Some(FrameBuffer::new(w, h));
ExprValue::Decimal(0.0)
})
.unwrap();
xbb.define_function("setpixel".to_owned(), 5, |args, io| {
let x = args[0].clone().into_decimal() as u32;
let y = args[1].clone().into_decimal() as u32;
let red = args[2].clone().into_decimal() as u8;
let green = args[3].clone().into_decimal() as u8;
let blue = args[4].clone().into_decimal() as u8;
match &mut io.frame {
Some(fb) => {
fb.set_pixel(x, y, red, green, blue, 255);
}
None => {}
}
ExprValue::Decimal(0.0)
})
.unwrap();
let mut xb = xbb.build();
let _ = xb.run(&format!("{}\n", code));
let errors = if xb.error_handler.had_errors
|| xb.error_handler.had_runtime_error
{
Some(xb.error_handler.errors.join("\n"))
} else {
None
};
(xb.get_io().s.clone(), xb.get_io().frame.clone(), errors)
};
msg.channel_id.say(&ctx, output).await.unwrap();
if let Some(fb) = &fb {
let buf = fb.as_png_vec();
msg.channel_id
.send_message(&ctx, |e| {
e.add_file(AttachmentType::Bytes {
data: Cow::Borrowed(&buf),
filename: "output.png".to_string(),
});
e
})
.await
.unwrap();
}
if let Some(e) = errors {
msg.channel_id.say(&ctx, e).await.unwrap();
}
}
"LIST" => {
msg.channel_id
.say(
&ctx,
format!(
"```\n{}\n```",
self.programs.lock().await[&msg.author.id].stringy_line_nums()
),
)
.await
.unwrap();
}
_ => {
let mut split = line.splitn(2, ' ');
let first = split.next().unwrap();
if let Ok(num) = first.parse::<u32>() {
match split.next() {
Some(x) => {
if x.is_empty() {
let _ = self
.programs
.lock()
.await
.get_mut(&msg.author.id)
.unwrap()
.code
.remove(&num);
return;
}
self.programs
.lock()
.await
.get_mut(&msg.author.id)
.unwrap()
.code
.insert(num, x.to_owned());
}
None => {
let _ = self
.programs
.lock()
.await
.get_mut(&msg.author.id)
.unwrap()
.code
.remove(&num);
}
}
}
}
}
}
if line == "!START" {
self.programs
.lock()
.await
.insert(msg.author.id, Program::new());
}
}
}
async fn ready(&self, _: Context, ready: Ready) {
@ -54,7 +307,9 @@ async fn main() {
let token = config.token;
let mut client = Client::builder(&token)
.event_handler(Handler)
.event_handler(Handler {
programs: Arc::new(Mutex::new(HashMap::new())),
})
.await
.expect("Error creating client");
if let Err(e) = client.start().await {


Loading…
Cancel
Save