aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-01-19 17:33:46 -0600
committerNathan Ringo <nathan@remexre.com>2024-01-19 17:33:46 -0600
commit401bc1c5485e26329598d59a140e51f70f58857c (patch)
tree6ddb4f146808550e2c70fe38deed0db59d5b8cce
parent87608eabbcbd105f5f5fecf7ab00a7bc93573477 (diff)
Fix diagrams, allow multiple roles.
-rw-r--r--discocaml/ast.ml10
-rw-r--r--discocaml/draw_tree.ml22
-rw-r--r--src/commands/discocaml.rs38
3 files changed, 54 insertions, 16 deletions
diff --git a/discocaml/ast.ml b/discocaml/ast.ml
index b5ebba3..a706a19 100644
--- a/discocaml/ast.ml
+++ b/discocaml/ast.ml
@@ -142,6 +142,16 @@ let parsetree_of_subexpr (ast : 'a ast) : expr -> Parsetree.expression =
(Pexp_apply
( Wrap.expression (Pexp_ident (Wrap.ident "+")),
[ (Nolabel, loop (subexpr l)); (Nolabel, loop (subexpr r)) ] ))
+ | Prim (`Sub, [| l; r |]) ->
+ Wrap.expression
+ (Pexp_apply
+ ( Wrap.expression (Pexp_ident (Wrap.ident "-")),
+ [ (Nolabel, loop (subexpr l)); (Nolabel, loop (subexpr r)) ] ))
+ | Prim (`Mul, [| l; r |]) ->
+ Wrap.expression
+ (Pexp_apply
+ ( Wrap.expression (Pexp_ident (Wrap.ident "*")),
+ [ (Nolabel, loop (subexpr l)); (Nolabel, loop (subexpr r)) ] ))
| Prim (p, xs) ->
failwith
("illegal Prim: " ^ [%derive.show: prim * expr index array] (p, xs))
diff --git a/discocaml/draw_tree.ml b/discocaml/draw_tree.ml
index fe3f037..6ea4ff2 100644
--- a/discocaml/draw_tree.ml
+++ b/discocaml/draw_tree.ml
@@ -2,17 +2,17 @@ open Ast
module IntSet = Set.Make (Int)
let add_node (fmt : Format.formatter) (i : expr index) (expr : expr) : unit =
- let label =
- match expr with
- | App _ -> "\"$\""
- | Int n -> Format.sprintf "\"%d\"" n
- | Lam (_, _) -> "\"λ\""
- | Prim (`Add, _) -> "\"+\""
- | Prim (`Sub, _) -> "\"-\""
- | Prim (`Mul, _) -> "\"*\""
- | Var n -> Format.sprintf "%S" n
- in
- Format.fprintf fmt " expr%d [label=%s];\n" i.index label
+ match expr with
+ | App _ ->
+ Format.fprintf fmt
+ " expr%d [fontname=\"CMU Typewriter Text Bold\", label=\"apply\"];\n"
+ i.index
+ | Int n -> Format.fprintf fmt " expr%d [label=\"%d\"];\n" i.index n
+ | Lam (_, _) -> Format.fprintf fmt " expr%d [label=\"λ\"];\n" i.index
+ | Prim (`Add, _) -> Format.fprintf fmt " expr%d [label=\"+\"];\n" i.index
+ | Prim (`Sub, _) -> Format.fprintf fmt " expr%d [label=\"-\"];\n" i.index
+ | Prim (`Mul, _) -> Format.fprintf fmt " expr%d [label=\"*\"];\n" i.index
+ | Var n -> Format.fprintf fmt " expr%d [label=%S];\n" i.index n
let add_expr_edges (ast : 'a ast) (fmt : Format.formatter)
(nodes : IntSet.t ref) : expr index -> unit =
diff --git a/src/commands/discocaml.rs b/src/commands/discocaml.rs
index fb6b05b..a24276d 100644
--- a/src/commands/discocaml.rs
+++ b/src/commands/discocaml.rs
@@ -17,7 +17,7 @@ use serenity::{
model::Permissions,
};
use sqlx::SqlitePool;
-use std::process::Stdio;
+use std::{collections::BTreeSet, process::Stdio};
use tokio::{io::AsyncWriteExt, process::Command};
use crate::utils::EnumAsArray;
@@ -26,7 +26,7 @@ use crate::utils::EnumAsArray;
#[serde(deny_unknown_fields)]
pub struct DiscocamlConfig {
pub command: Vec<String>,
- pub role: RoleId,
+ pub roles: BTreeSet<RoleId>,
}
#[derive(Debug, PartialEq, Serialize)]
@@ -117,8 +117,36 @@ pub fn command() -> CreateCommand {
async fn check_permissions(config: &DiscocamlConfig, member: Option<&Member>) -> Result<()> {
if let Some(member) = member {
- if !member.roles.contains(&config.role) {
- bail!("This command can only be used by <@&{}>.", config.role)
+ if !member.roles.iter().any(|role| config.roles.contains(role)) {
+ match config.roles.len() {
+ 0 => bail!("This command can not be used, because roles are not configured."),
+ 1 => bail!(
+ "This command can only be used by <@&{}>.",
+ config.roles.iter().next().unwrap()
+ ),
+ 2 => {
+ let mut iter = config.roles.iter();
+ bail!(
+ "This command can only be used by <@&{}> or <@&{}>.",
+ iter.next().unwrap(),
+ iter.next().unwrap()
+ )
+ }
+ _ => {
+ let mut iter = config.roles.iter();
+ let last = iter.next().unwrap();
+ let mut buf = String::new();
+ for role in iter {
+ buf.push_str("<@&");
+ buf.push_str(&role.to_string());
+ buf.push_str(">, ");
+ }
+ buf.push_str(", or <@&");
+ buf.push_str(&last.to_string());
+ buf.push('>');
+ bail!("This command can only be used by {}.", buf)
+ }
+ }
}
Ok(())
} else {
@@ -186,7 +214,7 @@ where
DiscocamlResponse::Error(err) => {
let err = anyhow!("got an error from discocaml: `{}`", err);
respond_with_error(&err, send).await;
- return Err(err);
+ Err(err)
}
}
}