aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-01-19 23:06:59 -0600
committerNathan Ringo <nathan@remexre.com>2024-01-19 23:06:59 -0600
commit6bea013cc69b8d11c24fd1e6041677e8e9310f66 (patch)
tree36587659c57a21a2ded67a8f3cb28e4decc9d709
parente9ce0f5ca752f044716c17384bd7ef2486d74805 (diff)
"Run mode" done.
-rw-r--r--discocaml/discocaml.ml31
-rw-r--r--src/commands/discocaml.rs63
2 files changed, 90 insertions, 4 deletions
diff --git a/discocaml/discocaml.ml b/discocaml/discocaml.ml
index e244e26..676cd67 100644
--- a/discocaml/discocaml.ml
+++ b/discocaml/discocaml.ml
@@ -18,7 +18,10 @@ type response_expr = { expr : string; has_redex : bool; note : string option }
[@@deriving to_yojson { exn = true }]
type response =
- [ `Error of string | `Expr of response_expr | `Graphviz of string ]
+ [ `Error of string
+ | `Expr of response_expr
+ | `Exprs of string option * string array
+ | `Graphviz of string ]
[@@deriving to_yojson { exn = true }]
let%expect_test _ =
@@ -31,6 +34,11 @@ let%expect_test _ =
(`Expr { expr = "foo"; has_redex = false; note = None }));
[%expect {| ["Expr",{"expr":"foo","has_redex":false,"note":null}] |}]
+let%expect_test _ =
+ Yojson.Safe.to_channel stdout
+ (response_to_yojson (`Exprs (Some "A", [| "B"; "C" |])));
+ [%expect {| ["Exprs","A",["B","C"]] |}]
+
let handle_request { expr; command } : response =
try
let buf = Lexing.from_string expr in
@@ -52,6 +60,16 @@ let handle_request { expr; command } : response =
| Some i -> Eval.reduce expr i
| None -> failwith "no redex"
in
+ let run_with (find_redex : expr ast -> expr index option) :
+ expr ast -> expr ast Seq.t =
+ let rec loop (expr : expr ast) : expr ast Seq.t =
+ Seq.cons expr (fun () ->
+ match find_redex expr with
+ | Some i -> loop (Eval.reduce expr i) ()
+ | None -> Nil)
+ in
+ loop
+ in
match command with
| `Parse -> expr_response expr
@@ -62,7 +80,16 @@ let handle_request { expr; command } : response =
expr_response ~note:"After one CBV step:"
(step_with Eval.find_redex_cbv expr)
| `DrawTree -> `Graphviz (Draw_tree.draw_tree expr)
- | `RunCBN | `RunCBV -> failwith "not implemented"
+ | `RunCBN ->
+ `Exprs
+ ( Some "Evaluating with CBN:",
+ run_with Eval.find_redex_cbn expr
+ |> Seq.take 100 |> Seq.map show_expr |> Array.of_seq )
+ | `RunCBV ->
+ `Exprs
+ ( Some "Evaluating with CBV:",
+ run_with Eval.find_redex_cbv expr
+ |> Seq.take 100 |> Seq.map show_expr |> Array.of_seq )
with
| Eval.NotARedex expr -> `Error ("not a redex: " ^ show_expr expr)
| Failure msg -> `Error msg
diff --git a/src/commands/discocaml.rs b/src/commands/discocaml.rs
index ed00185..6defac0 100644
--- a/src/commands/discocaml.rs
+++ b/src/commands/discocaml.rs
@@ -72,10 +72,32 @@ pub enum DiscocamlCommand {
///
/// assert_eq!(out, expected);
/// ```
+///
+/// ```
+/// # use lambo::{commands::discocaml::*, utils::EnumAsArray};
+/// # use serde::Deserialize;
+/// # use serde_json::Deserializer;
+///
+/// let example = r#"["Exprs", "A", ["B", "C"]]"#;
+/// let expected = DiscocamlResponse::Exprs(
+/// "A".to_string(),
+/// vec![
+/// "B".to_string(),
+/// "C".to_string(),
+/// ],
+/// );
+///
+/// let mut de = Deserializer::from_str(&example);
+/// let out = DiscocamlResponse::deserialize(EnumAsArray(&mut de)).unwrap();
+/// de.end().unwrap();
+///
+/// assert_eq!(out, expected);
+/// ```
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub enum DiscocamlResponse {
Expr(DiscocamlResponseExpr),
+ Exprs(Option<String>, Vec<String>),
Error(String),
Graphviz(String),
}
@@ -196,6 +218,39 @@ where
send(CreateInteractionResponse::Message(res)).await?;
Ok(())
}
+ DiscocamlResponse::Exprs(note, exprs) => {
+ let mut msg = String::new();
+ if let Some(note) = &note {
+ msg.push_str(note);
+ msg.push('\n');
+ }
+
+ let mut msg_chars = msg.chars().count();
+ for expr in exprs {
+ let mut bullet = String::new();
+ bullet.push_str("1. ```ocaml\n");
+ for line in escape_code(&expr).lines() {
+ bullet.push_str(" ");
+ bullet.push_str(line);
+ bullet.push('\n');
+ }
+ bullet.push_str(" ```\n");
+ let bullet_chars = bullet.chars().count();
+ if msg_chars + bullet_chars > 1995 {
+ msg.push_str("1. …\n");
+ msg_chars += 5;
+ assert!(msg_chars < 2000);
+ break;
+ }
+ msg.push_str(&bullet);
+ msg_chars += bullet_chars;
+ }
+ assert_eq!(msg.chars().count(), msg_chars);
+
+ let msg = CreateInteractionResponseMessage::new().content(msg);
+ send(CreateInteractionResponse::Message(msg)).await?;
+ Ok(())
+ }
DiscocamlResponse::Graphviz(dot) => {
let png = match run_dot(&dot).await {
Ok(png) => png,
@@ -290,6 +345,11 @@ async fn run_dot(dot: &str) -> Result<BString> {
Ok(BString::new(output.stdout))
}
+fn escape_code(s: &str) -> String {
+ // TODO
+ s.to_string()
+}
+
fn expr_response_message(
expr: &DiscocamlResponseExpr,
rowid: i64,
@@ -300,8 +360,7 @@ fn expr_response_message(
msg.push('\n');
}
msg.push_str("```ocaml\n");
- // TODO: Escaping
- msg.push_str(&expr.expr);
+ msg.push_str(&escape_code(&expr.expr));
msg.push_str("```\n");
CreateInteractionResponseMessage::new()