From c5c961b1a356f02fe45c4b09f408a4856885e39d Mon Sep 17 00:00:00 2001 From: Aster Date: Fri, 10 Nov 2023 13:36:11 +0000 Subject: [PATCH 1/8] convert to multi-project framework --- .gitignore | 8 +- Cargo.toml | 26 +- projects/cas3-core/Cargo.toml | 14 + .../cas3-core/lang}/aliases.sexp | 0 {lang => projects/cas3-core/lang}/attrs.sexp | 0 .../cas3-core/lang}/calculus.sexp | 0 .../cas3-core/lang}/startup.sexp | 0 .../cas3-core/lang}/systems.sexp | 0 {src => projects/cas3-core/src}/main.rs | 0 projects/cas3-jupyter/Cargo.toml | 42 +++ projects/cas3-jupyter/client/kernel.js | 71 +++++ projects/cas3-jupyter/client/version.txt | 1 + projects/cas3-jupyter/package.json | 7 + projects/cas3-jupyter/readme.md | 2 + projects/cas3-jupyter/src/config/mod.rs | 10 + projects/cas3-jupyter/src/executor/mod.rs | 73 +++++ projects/cas3-jupyter/src/main.rs | 80 ++++++ projects/cas3-jupyter/src/protocol/display.rs | 1 + projects/cas3-jupyter/src/protocol/mod.rs | 36 +++ projects/cas3-jupyter/tests/collection.vk | 1 + projects/cas3-jupyter/tests/literals.vk | 15 ++ projects/cas3-jupyter/tests/main.rs | 27 ++ projects/cas3-jupyter/tests/readme.md | 5 + .../third_party/CodeMirror/LICENSE | 21 ++ .../third_party/CodeMirror/README.md | 6 + .../CodeMirror/addons/lint/lint.css | 71 +++++ .../CodeMirror/addons/lint/lint.js | 255 ++++++++++++++++++ .../cas3-jupyter/third_party/rust/LICENSE.md | 3 + .../third_party/rust/rust-logo-32x32.png | Bin 0 -> 1981 bytes .../third_party/rust/rust-logo-64x64.png | Bin 0 -> 4964 bytes 30 files changed, 761 insertions(+), 14 deletions(-) create mode 100644 projects/cas3-core/Cargo.toml rename {lang => projects/cas3-core/lang}/aliases.sexp (100%) rename {lang => projects/cas3-core/lang}/attrs.sexp (100%) rename {lang => projects/cas3-core/lang}/calculus.sexp (100%) rename {lang => projects/cas3-core/lang}/startup.sexp (100%) rename {lang => projects/cas3-core/lang}/systems.sexp (100%) rename {src => projects/cas3-core/src}/main.rs (100%) create mode 100644 projects/cas3-jupyter/Cargo.toml create mode 100644 projects/cas3-jupyter/client/kernel.js create mode 100644 projects/cas3-jupyter/client/version.txt create mode 100644 projects/cas3-jupyter/package.json create mode 100644 projects/cas3-jupyter/readme.md create mode 100644 projects/cas3-jupyter/src/config/mod.rs create mode 100644 projects/cas3-jupyter/src/executor/mod.rs create mode 100644 projects/cas3-jupyter/src/main.rs create mode 100644 projects/cas3-jupyter/src/protocol/display.rs create mode 100644 projects/cas3-jupyter/src/protocol/mod.rs create mode 100644 projects/cas3-jupyter/tests/collection.vk create mode 100644 projects/cas3-jupyter/tests/literals.vk create mode 100644 projects/cas3-jupyter/tests/main.rs create mode 100644 projects/cas3-jupyter/tests/readme.md create mode 100644 projects/cas3-jupyter/third_party/CodeMirror/LICENSE create mode 100644 projects/cas3-jupyter/third_party/CodeMirror/README.md create mode 100644 projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.css create mode 100644 projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.js create mode 100644 projects/cas3-jupyter/third_party/rust/LICENSE.md create mode 100644 projects/cas3-jupyter/third_party/rust/rust-logo-32x32.png create mode 100644 projects/cas3-jupyter/third_party/rust/rust-logo-64x64.png diff --git a/.gitignore b/.gitignore index 79bf893..a0cb275 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ -/target -history.txt \ No newline at end of file +## IDE +.idea/ + +## Rust +target/ +history.txt diff --git a/Cargo.toml b/Cargo.toml index bd4fc52..1b5a769 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,16 @@ -[package] -name = "cas3" -version = "0.1.0" -edition = "2021" +[workspace] +resolver = "2" +members = ["projects/*"] +default-members = [ + "projects/valkyrie-interpreter", + "projects/valkyrie-jupyter", +] +exclude = [ + "projects/playground", + "projects/.DS_Store", +] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[profile.release] +lto = true +panic = "abort" -[dependencies] -cairo-rs = { version = "0.18.2", features = ["svg"] } -num-bigint = "0.4.4" -num-traits = "0.2.17" -ordered-float = "4.1.0" -peg = "0.8.1" -rustyline = { version = "12.0.0", features = ["derive", "custom-bindings"] } diff --git a/projects/cas3-core/Cargo.toml b/projects/cas3-core/Cargo.toml new file mode 100644 index 0000000..bd4fc52 --- /dev/null +++ b/projects/cas3-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cas3" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cairo-rs = { version = "0.18.2", features = ["svg"] } +num-bigint = "0.4.4" +num-traits = "0.2.17" +ordered-float = "4.1.0" +peg = "0.8.1" +rustyline = { version = "12.0.0", features = ["derive", "custom-bindings"] } diff --git a/lang/aliases.sexp b/projects/cas3-core/lang/aliases.sexp similarity index 100% rename from lang/aliases.sexp rename to projects/cas3-core/lang/aliases.sexp diff --git a/lang/attrs.sexp b/projects/cas3-core/lang/attrs.sexp similarity index 100% rename from lang/attrs.sexp rename to projects/cas3-core/lang/attrs.sexp diff --git a/lang/calculus.sexp b/projects/cas3-core/lang/calculus.sexp similarity index 100% rename from lang/calculus.sexp rename to projects/cas3-core/lang/calculus.sexp diff --git a/lang/startup.sexp b/projects/cas3-core/lang/startup.sexp similarity index 100% rename from lang/startup.sexp rename to projects/cas3-core/lang/startup.sexp diff --git a/lang/systems.sexp b/projects/cas3-core/lang/systems.sexp similarity index 100% rename from lang/systems.sexp rename to projects/cas3-core/lang/systems.sexp diff --git a/src/main.rs b/projects/cas3-core/src/main.rs similarity index 100% rename from src/main.rs rename to projects/cas3-core/src/main.rs diff --git a/projects/cas3-jupyter/Cargo.toml b/projects/cas3-jupyter/Cargo.toml new file mode 100644 index 0000000..f09a59f --- /dev/null +++ b/projects/cas3-jupyter/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "cas3-jupyter" +version = "0.0.0" +authors = ["Aster <192607617@qq.com>"] +description = "Jupyter Kernel for Valkyrie Language" +repository = "https://github.com/nyar-vm/valkyrie-jupyter" +documentation = "https://docs.rs/jupyter-valkyrie" +readme = "readme.md" +license = "MPL-2.0" +edition = "2021" +exclude = ["package.json", "tests/**"] + +[[bin]] +name = "jupyter-valkyrie" +path = "src/main.rs" + +[dependencies] +url = "2.4.1" +async-trait = "0.1.73" +tracing-subscriber = "0.3.17" +clap = { version = "4.4.2", features = ["derive"] } + +[dependencies.jupyter] +version = "0.2.1" +#path = 'C:\Users\Dell\CLionProjects\jupyter-protocol\projects\jupyter' + +[dependencies.jupyter-derive] +version = "0.0.2" +#path = "C:\\Users\\Dell\\CLionProjects\\jupyter-protocol\\projects\\jupyter-derive" + +[dependencies.valkyrie-interpreter] +version = "0.0.*" +path = "../valkyrie-interpreter" + +[dev-dependencies] +tokio = "1.32.0" + +[features] +default = [] + +[package.metadata.docs.rs] +all-features = true diff --git a/projects/cas3-jupyter/client/kernel.js b/projects/cas3-jupyter/client/kernel.js new file mode 100644 index 0000000..bb404b2 --- /dev/null +++ b/projects/cas3-jupyter/client/kernel.js @@ -0,0 +1,71 @@ +// Copyright 2020 The Evcxr Authors. +// +// Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +define([ + 'require', + 'base/js/namespace', + 'codemirror/lib/codemirror', + 'base/js/events', + './lint.js' +], function (requireJs, Jupyter, CodeMirror, events) { + "use strict"; + + function initCell(cell) { + // It could be nice to show errors and warnings in the gutter as well. + // We can enable that with the following line, however unfortunately + // that messes up the horizontal scroll until the user clicks in editor. + // We can sort of fix that by delaying setting of gutters by 1 second. + // That's too hacky though. We probably need to wait until some + // particular thing has been initialized. Until we figure out what that + // thing is, we leave the gutters off. + + // cell.code_mirror.setOption('gutters', ["CodeMirror-lint-markers"]) + cell.code_mirror.setOption('lint', true); + } + + function cellCreated(event, nbcell) { + initCell(nbcell.cell); + } + + function initExistingCells() { + for (let cell of Jupyter.notebook.get_cells()) { + initCell(cell); + } + } + + function lintText(text) { + return new Promise(function (resolve, reject) { + let cargoCheckComm = Jupyter.notebook.kernel.comm_manager.new_comm('evcxr-cargo-check', { + code: text, + }); + cargoCheckComm.on_msg(function (msg) { + let found = []; + for (let problem of msg.content.data.problems) { + found.push({ + from: CodeMirror.Pos(problem.start_line - 1, problem.start_column - 1), + to: CodeMirror.Pos(problem.end_line - 1, problem.end_column - 1), + severity: problem.severity, + message: problem.message, + }); + } + resolve(found); + }); + }); + } + + return { + onload: function () { + $('head').append( + $('').attr('href', requireJs.toUrl('./lint.css')) + ) + events.on('create.Cell', cellCreated); + initExistingCells(); + CodeMirror.registerHelper("lint", "rust", lintText); + } + } + +}); diff --git a/projects/cas3-jupyter/client/version.txt b/projects/cas3-jupyter/client/version.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/projects/cas3-jupyter/client/version.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/projects/cas3-jupyter/package.json b/projects/cas3-jupyter/package.json new file mode 100644 index 0000000..7471a23 --- /dev/null +++ b/projects/cas3-jupyter/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "scripts": { + "p": "cargo publish --allow-dirty", + "i": "cargo install --path . --debug" + } +} diff --git a/projects/cas3-jupyter/readme.md b/projects/cas3-jupyter/readme.md new file mode 100644 index 0000000..db86903 --- /dev/null +++ b/projects/cas3-jupyter/readme.md @@ -0,0 +1,2 @@ +Title +===== diff --git a/projects/cas3-jupyter/src/config/mod.rs b/projects/cas3-jupyter/src/config/mod.rs new file mode 100644 index 0000000..fd1543c --- /dev/null +++ b/projects/cas3-jupyter/src/config/mod.rs @@ -0,0 +1,10 @@ +pub struct ValkyrieConfig { + pub running_time: bool, + pub image_max_pixel: usize, +} + +impl Default for ValkyrieConfig { + fn default() -> Self { + ValkyrieConfig { running_time: false, image_max_pixel: 1024 * 768 } + } +} diff --git a/projects/cas3-jupyter/src/executor/mod.rs b/projects/cas3-jupyter/src/executor/mod.rs new file mode 100644 index 0000000..66b3df0 --- /dev/null +++ b/projects/cas3-jupyter/src/executor/mod.rs @@ -0,0 +1,73 @@ +use crate::{config::ValkyrieConfig, DisplayKeywords, DisplayNumber}; +use jupyter::{to_value, value_type::HtmlText, ExecutionRequest, JupyterError, JupyterKernelSockets, JupyterMessage}; +use valkyrie_interpreter::{ValkyrieError, ValkyrieVM, ValkyrieValue}; + +pub struct ValkyrieExecutor { + pub(crate) vm: ValkyrieVM, + pub(crate) sockets: JupyterKernelSockets, + pub(crate) config: ValkyrieConfig, +} + +impl Default for ValkyrieExecutor { + fn default() -> Self { + ValkyrieExecutor { vm: ValkyrieVM::default(), sockets: Default::default(), config: ValkyrieConfig::default() } + } +} + +impl ValkyrieExecutor { + pub(crate) async fn repl_parse_and_run(&mut self, code: &ExecutionRequest) -> Result<(), ValkyrieError> { + let file = self.vm.load_snippet(&code.code, &format!("Cell{}", code.execution_count)); + for task in self.vm.execute_script(file).await { + match task { + Ok(v) => self.send_value(v, &code.header).await, + Err(e) => self.sockets.send_executed(JupyterError::custom(format!("Error: {}", e)), &code.header).await, + } + } + Ok(()) + } + + pub(crate) async fn send_value(&self, value: ValkyrieValue, parent: &JupyterMessage) { + match value { + // never type never sends + ValkyrieValue::Nothing => {} + ValkyrieValue::Null => self.sockets.send_executed(DisplayKeywords::new("null"), parent).await, + ValkyrieValue::Unit => self.sockets.send_executed(DisplayKeywords::new("( )"), parent).await, + ValkyrieValue::Boolean(v) => self.sockets.send_executed(DisplayKeywords::new(v), parent).await, + ValkyrieValue::Number(v) => self.sockets.send_executed(DisplayNumber::new(v), parent).await, + ValkyrieValue::Unicode(v) => self.sockets.send_executed(v.to_string(), parent).await, + ValkyrieValue::UTF8String(v) => self.sockets.send_executed(v.get().clone(), parent).await, + ValkyrieValue::Bytes(_) => { + todo!() + } + ValkyrieValue::Class(_) => { + todo!() + } + ValkyrieValue::Variant(_) => { + todo!() + } + ValkyrieValue::NDArray(_) => { + todo!() + } + ValkyrieValue::Image(_) => { + todo!() + } + ValkyrieValue::Html(v) => { + self.sockets.send_executed(HtmlText::new(v), parent).await; + } + ValkyrieValue::Uninitialized => { + todo!() + } + ValkyrieValue::List(v) => match to_value(v) { + Ok(o) => self.sockets.send_executed(o, parent).await, + Err(_) => {} + }, + ValkyrieValue::Dict(v) => match to_value(v) { + Ok(o) => self.sockets.send_executed(o, parent).await, + Err(_) => {} + }, + // ValkyrieValue::DataFrame(_) => { + // todo!() + // } + } + } +} diff --git a/projects/cas3-jupyter/src/main.rs b/projects/cas3-jupyter/src/main.rs new file mode 100644 index 0000000..3920ca0 --- /dev/null +++ b/projects/cas3-jupyter/src/main.rs @@ -0,0 +1,80 @@ +#![deny(missing_debug_implementations, missing_copy_implementations)] +#![warn(missing_docs, rustdoc::missing_crate_level_docs)] +#![doc = include_str!("../readme.md")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/oovm/shape-rs/dev/projects/images/Trapezohedron.svg")] +#![doc(html_favicon_url = "https://raw.githubusercontent.com/oovm/shape-rs/dev/projects/images/Trapezohedron.svg")] + +use std::fmt::{Debug, Formatter}; + +use std::path::PathBuf; + +use crate::executor::ValkyrieExecutor; +use clap::{Parser, Subcommand}; +use jupyter::{InstallAction, JupyterResult, OpenAction, StartAction, UninstallAction}; +use std::io::Write; +use url::Url; + +mod config; +mod executor; +mod protocol; + +pub use crate::protocol::display::{DisplayKeywords, DisplayNumber, DisplayText}; + +/// +#[derive(Debug, Parser)] +#[command(author, version, about, long_about = None)] +pub struct JupyterApplication { + /// Sets a custom config file + #[arg(short, long, value_name = "FILE")] + config: Option, + /// Turn debugging information on + #[arg(short, long, action = clap::ArgAction::Count)] + debug: u8, + #[command(subcommand)] + command: JupyterCommands, +} + +/// The subcommands of the application +#[derive(Subcommand)] +enum JupyterCommands { + Open(Box), + Start(Box), + Install(Box), + Uninstall(Box), +} + +impl Debug for JupyterCommands { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + unreachable!("{}", f.alternate()) + } +} + +impl JupyterApplication { + /// Run the application + pub fn run(&self) -> JupyterResult<()> { + let config = ValkyrieExecutor::default(); + match &self.command { + JupyterCommands::Open(v) => v.run(), + JupyterCommands::Start(v) => v.run(config), + JupyterCommands::Install(v) => v.run(config), + JupyterCommands::Uninstall(v) => v.run(config), + } + } +} + +fn main() -> JupyterResult<()> { + std::panic::set_hook(Box::new(|info| { + let mut host_stderr = std::io::stderr().lock(); + match info.location() { + None => {} + Some(s) => match Url::from_file_path(s.file()) { + Ok(o) => { + writeln!(host_stderr, "{}:{}:{}", o, s.line(), s.column()).ok(); + } + Err(_) => {} + }, + } + })); + tracing_subscriber::fmt::init(); + JupyterApplication::parse().run() +} diff --git a/projects/cas3-jupyter/src/protocol/display.rs b/projects/cas3-jupyter/src/protocol/display.rs new file mode 100644 index 0000000..4563e55 --- /dev/null +++ b/projects/cas3-jupyter/src/protocol/display.rs @@ -0,0 +1 @@ +use super::*; diff --git a/projects/cas3-jupyter/src/protocol/mod.rs b/projects/cas3-jupyter/src/protocol/mod.rs new file mode 100644 index 0000000..88d99a0 --- /dev/null +++ b/projects/cas3-jupyter/src/protocol/mod.rs @@ -0,0 +1,36 @@ +use crate::executor::ValkyrieExecutor; +use jupyter::{ + value_type::{JupyterContext, JupyterTheme}, + Executed, ExecutionReply, ExecutionRequest, JupyterConnection, JupyterError, JupyterKernelProtocol, LanguageInfo, Value, +}; +use jupyter_derive::include_png32; + +pub mod display; + +impl JupyterKernelProtocol for ValkyrieExecutor { + fn language_info(&self) -> LanguageInfo { + let mut info = + LanguageInfo::new("valkyrie", "Valkyrie").with_syntax("scala", "scala").with_version(env!("CARGO_PKG_VERSION")); + info.png_32 = include_png32!(); + info.png_64 = include_png32!(); + return info; + } + + fn connected(&mut self, context: JupyterConnection) { + self.sockets = context.sockets; + } + + async fn running(&mut self, code: ExecutionRequest) -> ExecutionReply { + match self.repl_parse_and_run(&code).await { + Ok(_) => ExecutionReply::new(true), + Err(e) => { + self.sockets.send_executed(JupyterError::custom(e.to_string()), &code.header).await; + ExecutionReply::new(false) + } + } + } + + fn running_time(&self, time: f64) -> String { + if self.config.running_time { format!("Elapsed time: {:.2} seconds.", time) } else { String::new() } + } +} diff --git a/projects/cas3-jupyter/tests/collection.vk b/projects/cas3-jupyter/tests/collection.vk new file mode 100644 index 0000000..4b1004b --- /dev/null +++ b/projects/cas3-jupyter/tests/collection.vk @@ -0,0 +1 @@ +(1, 2, a: 3);; diff --git a/projects/cas3-jupyter/tests/literals.vk b/projects/cas3-jupyter/tests/literals.vk new file mode 100644 index 0000000..e18909b --- /dev/null +++ b/projects/cas3-jupyter/tests/literals.vk @@ -0,0 +1,15 @@ +true +false + +nil +null + +0 +1 +2 +3 + +"string" +"string formatter { 0 }" + +r"raw string" diff --git a/projects/cas3-jupyter/tests/main.rs b/projects/cas3-jupyter/tests/main.rs new file mode 100644 index 0000000..99f81dc --- /dev/null +++ b/projects/cas3-jupyter/tests/main.rs @@ -0,0 +1,27 @@ +#[test] +fn ready() { + println!("it works!") +} + +use std::path::Path; +use valkyrie_interpreter::ValkyrieVM; + +#[tokio::test] +async fn tests() { + debug_wrong("tests/literals.vk").await.unwrap(); + debug_wrong("tests/collection.vk").await.unwrap(); +} + +async fn debug_wrong>(file: P) -> std::io::Result<()> { + let mut vm = ValkyrieVM::default(); + let file = vm.load_file(file.as_ref().canonicalize()?)?; + for i in vm.execute_script(file).await { + match i { + Ok(o) => { + println!("{:#?}", o); + } + Err(e) => e.as_report().eprint(vm.as_ref())?, + } + } + Ok(()) +} diff --git a/projects/cas3-jupyter/tests/readme.md b/projects/cas3-jupyter/tests/readme.md new file mode 100644 index 0000000..649841b --- /dev/null +++ b/projects/cas3-jupyter/tests/readme.md @@ -0,0 +1,5 @@ +## Tests + +```bash +wee test +``` diff --git a/projects/cas3-jupyter/third_party/CodeMirror/LICENSE b/projects/cas3-jupyter/third_party/CodeMirror/LICENSE new file mode 100644 index 0000000..ff7db4b --- /dev/null +++ b/projects/cas3-jupyter/third_party/CodeMirror/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2017 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/projects/cas3-jupyter/third_party/CodeMirror/README.md b/projects/cas3-jupyter/third_party/CodeMirror/README.md new file mode 100644 index 0000000..74180d4 --- /dev/null +++ b/projects/cas3-jupyter/third_party/CodeMirror/README.md @@ -0,0 +1,6 @@ +This directory contains code from [CodeMirror](https://github.com/codemirror/CodeMirror). + +See LICENSE file for license details. + +Code here may have had some modifications from the original. + diff --git a/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.css b/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.css new file mode 100644 index 0000000..0871865 --- /dev/null +++ b/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.css @@ -0,0 +1,71 @@ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: #ffd; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: black; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-mark-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); +} + +.CodeMirror-lint-marker { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} diff --git a/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.js b/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.js new file mode 100644 index 0000000..326f3c6 --- /dev/null +++ b/projects/cas3-jupyter/third_party/CodeMirror/addons/lint/lint.js @@ -0,0 +1,255 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +define([ + 'codemirror/lib/codemirror', +], +function(CodeMirror) { + "use strict"; + var GUTTER_ID = "CodeMirror-lint-markers"; + + function showTooltip(cm, e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme; + tt.appendChild(content.cloneNode(true)); + if (cm.state.lint.options.selfContain) + cm.getWrapperElement().appendChild(tt); + else + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function showTooltipFor(cm, e, content, node) { + var tooltip = showTooltip(cm, e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n && n.nodeType == 11) n = n.host; + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + + function LintState(cm, options, hasGutter) { + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; + this.waitingFor = 0 + } + + function parseOptions(_cm, options) { + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + return options; + } + + function clearMarks(cm) { + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; + } + + function makeMarker(cm, labels, severity, multiple, tooltips) { + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple"; + } + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(cm, e, labels, inner); + }); + + return marker; + } + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; + } + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; + } + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!severity) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity; + if (typeof ann.messageHTML != 'undefined') { + tip.innerHTML = ann.messageHTML; + } else { + tip.appendChild(document.createTextNode(ann.message)); + } + return tip; + } + + function lintAsync(cm, getAnnotations, passOptions) { + var state = cm.state.lint + var id = ++state.waitingFor + function abort() { + id = -1 + cm.off("change", abort) + } + cm.on("change", abort) + getAnnotations(cm.getValue(), function(annotations, arg2) { + cm.off("change", abort) + if (state.waitingFor != id) return + if (arg2 && annotations instanceof CodeMirror) annotations = arg2 + cm.operation(function() {updateLinting(cm, annotations)}) + }, passOptions, cm); + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + /* + * Passing rules in `options` property prevents JSHint (and other linters) from complaining + * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. + */ + var passOptions = options.options || options; + var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!getAnnotations) return; + if (options.async || getAnnotations.async) { + lintAsync(cm, getAnnotations, passOptions) + } else { + var annotations = getAnnotations(cm.getValue(), passOptions, cm); + if (!annotations) return; + if (annotations.then) annotations.then(function(issues) { + cm.operation(function() {updateLinting(cm, issues)}) + }); + else cm.operation(function() {updateLinting(cm, annotations)}) + } + } + + function updateLinting(cm, annotationsNotSorted) { + clearMarks(cm); + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + // filter out duplicate messages + var message = []; + anns = anns.filter(function(item) { return message.indexOf(item.message) > -1 ? false : message.push(item.message) }); + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!severity) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + // use original annotations[line] to show multiple messages + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, annotations[line].length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + if (!state) return; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + } + + function popupTooltips(cm, annotations, e) { + var target = e.target || e.srcElement; + var tooltip = document.createDocumentFragment(); + for (var i = 0; i < annotations.length; i++) { + var ann = annotations[i]; + tooltip.appendChild(annotationTooltip(ann)); + } + showTooltipFor(cm, e, tooltip, target); + } + + function onMouseOver(cm, e) { + var target = e.target || e.srcElement; + if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; + var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; + var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); + + var annotations = []; + for (var i = 0; i < spans.length; ++i) { + var ann = spans[i].__annotation; + if (ann) annotations.push(ann); + } + if (annotations.length) popupTooltips(cm, annotations, e); + } + + CodeMirror.defineOption("lint", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + if (cm.state.lint.options.lintOnChange !== false) + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + clearTimeout(cm.state.lint.timeout); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + if (state.options.lintOnChange !== false) + cm.on("change", onChange); + if (state.options.tooltips != false && state.options.tooltips != "gutter") + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } + }); + + CodeMirror.defineExtension("performLint", function() { + if (this.state.lint) startLinting(this); + }); +}); diff --git a/projects/cas3-jupyter/third_party/rust/LICENSE.md b/projects/cas3-jupyter/third_party/rust/LICENSE.md new file mode 100644 index 0000000..50a1ccf --- /dev/null +++ b/projects/cas3-jupyter/third_party/rust/LICENSE.md @@ -0,0 +1,3 @@ + +The Rust and Cargo logos (bitmap and vector) are owned by Mozilla and distributed under the terms of the [Creative Commons Attribution license (CC-BY)](https://creativecommons.org/licenses/by/4.0/). +See [Rust Legal Policies · The Rust Programming Language](https://www.rust-lang.org/en-US/legal.html) diff --git a/projects/cas3-jupyter/third_party/rust/rust-logo-32x32.png b/projects/cas3-jupyter/third_party/rust/rust-logo-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..d572cbf027a3c3600a1f4c35bb9c909b87d67c62 GIT binary patch literal 1981 zcmV;u2SWIXP)+qP}nwr$(CZQJ(uJzm>3X6{Z;Pj^>k=6UFjiQbJjv9Z61 zGR{d0lj-_x7hO(7MgxzFk&D$P00&2F)<@|B{-4Pp*X_C-lN95M#`}Y#FLo*l|GM{a z&cVUrOqZBrV^ne<&n%7XIo4S7X;fXjr>A_g5pxIdAd?{1?z%j~5p*R~-)xTWKe$oP zPc4dAwP{+(ePm<;y^VkuOQpL+Qw0&oi%=Dbl{B#@baiEyWTk9T;1z};SMIt3!!d&c z+SgaBny7!+a%tu~L)7aBl;t~AA3AuoKjndgk`Nh^Rb3^{YNMd&nT zCY509KEM6)=L;d~>pfXQBf@}Kzz_k2m!rzcikz-6H?X;&FN3TMfJVAAM_20T9jN2b z#VbAOYNc}NDxgXSxoC%F>12z1h5qr?S3{w6B?*5vaza)ji1|_B993=tssXcYgga>2 z4!BdG0&EDJD=@79<9br6^&AN~U5Qx{c#RHn+6D{I#;B6a_e)>B4>dnj{*!&v6J1I) z_ELr8C(b^{tf0WeKW!&+I&h$BWU5M;fqIje=X0fralnVP$+7D$2*6BJ_00e0Z@usR zJ{TC6W&B<*2w9mZYzREYtv=3u zblTpAZv|I~KtxbL5mZ3|gyH(ukL}@iEKs%RwxD;oP%w2W{8lf11g4|SErWsvY zsjqk7bTxKCB3T22HUUavFzkK zYvda_VvYG2>Ecm;G~(H#OBufpdN6`dGolz&K}7&s=S)aN=p?Ficp6wogv|x+bI~)E zi~LmgWWv$FIW71h1?SdlV#~jW9a8r+T8~)Z;zshCVwEcxg#2g%vt)s|7i0rM( zbqXtLyXqr`h+GAnMF%hDEJ2P2MN|28D0rKih!C&@5fnp2cGLfE00I*n zhnnE2Am-o#07jIxxt-+UDvJ`u0-RbG^NGv4lgny@e*er_>O}!!zc#@?OI)-|6_1_v9#NL z=%~^$FVOjkA_#~g@Opc^R{=8hr+9HQOY{T`Ua4AZ{_e)BdrBl6R4d|*0fSK;O^1ll zcKde(mt%ml+aW6oR{`6BAVBM=6@iU_+nt6=R6Wt;O%Ndu;Kd!}1Gl@8C9`3zt~Yk4 zmb}&^m}DOBvc(FQr2(5qWJExS(oO(_!t9DHp^yRZ0NVo_0u==WXdm|$_$Z1w5N)@; zC}J&Q{Eeyby9@9V*4$Cc!vfN!tC~lxjbEB-ZmJ;rL?5LqwHQ%i3`8tL9Zn_)4oFA)Q_%7pZ3+{- z6A{!G#1Kf+l!jL+rDoq?+y^EYM@Bf&s8+m!5yfbPP_%!7i;BFU@Up^R|Fbc)@jCEk$11p9``$~y z3kolRybgxwBVDOupjmupjI15eQzMFtDC51Wj;QdLqE^fn6v_@7KB7*HihQE5AjlH} zX9>#ic=A76M9u@2rj@|@_y#2t5DeWWj55ajB|;UzMFfCyS2kR zgyy1-bm|=YnHo70IEzV8qyiice28)|zEL3t#+0B|uYTZ?tdW>FYkTw{`>eARolIkJ z+B(S(wp^xYHi@FE^t#cg%1cm5- zj-%5QBg(TgSkSE3{utX`8rxrlmqz8i)jl@{LU>V)xdD-TfDeEwEfrusV%!SV-Oz{z z|Bulwj2V|Gzf|khEO8YlarTK5kloi^hT#nMVT z2-cEl!PJQd?`h@%Kp2MXw8|0;XLOJ0uQuX~O*NGs$EtN#rWusnM?w^G;}DH#jHDLI ziO?g8Mo+zwzhi{2x~;4Rj9?hD*BVPODN;^P&71y&X3z&xYd6bKO3v_yWJH89TBlw_ zavuoD0~XyZN$jb>Nlb$C#xN;Uj;Wj%yng|BrN6)Nj4%8$z0I(SvGtcw7+?4eT{(R; zOYC2P&CA`{idiZ9ib+F`*l}$phjX?9RDd6gqFA4n$Bi-58f&XSmC5ig?wj4b8{Ep` P00000NkvXXu0mjf?TVkL literal 0 HcmV?d00001 diff --git a/projects/cas3-jupyter/third_party/rust/rust-logo-64x64.png b/projects/cas3-jupyter/third_party/rust/rust-logo-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..1eaa7709d12eab587139c23898ed6a0cec92e698 GIT binary patch literal 4964 zcmV-q6PxUbP)9c-T&J5|<@a z)xGEJM_OLBWI6Woa~}T0tnWMfo^uVo|A}7y>5slO`w86Yf0B6FXFtKcEr#LtX!Ri? z9)YtEB|eb+H8o}5e;|GXS}CV-Cb$C+bua59o9iW+m({_$;SU@N@fh-SRkUF|vpiTn zVjRXhCez6)vvjm3v;EYtt~Yg)GVgazoay>*Uiva8J_NtwQ0cn&z~5luI_ax$y>#;B zMfrqQ%GqJL{4ktd9<0BlW>d%1YMa-LGlkz=u2;J?LzJSmHqVUj@7CkZZP=feu2Z@Y z;p6cueb?>ooY?xk=$tMQzlHaAoy1G8<0TLWdw;xMkB?ukN5g7ZtXjMQ(My>%=*r3(&-{3 z_LhV7SVg8TQr9H}oI15L-`d{#!U(tH7hQvR;WbXcEbIBYT+I(wgM$mpA6O6hi;bUw z`3*ZtORKTk8>);>*A*!dQo!x_6x^rsvn^v@B0&?hl+xC8>crN>FgA;WwQNm<&+no= ze%kx!*=#c3+1Y|{4dS_<_88Zqzp!}K-u`NLH83=?ga>YS*8RkVp;@)mMUg@xfs1eB z{qWn6d;wmPfXy_C)+iB9Zcp`Hxa-1NYDzYJFqxEVFW}Y>dneaoatZF|M5gMQg*eD@nlHn8a6Cgb!`5GHyvw zH+;Z5xRSSd!1lw6{Gq$|5B_-X!uqf4kbf~o{2sCUkdrg7yRfv5PE4now7Kesub;(_ z;Eyun7m_&^$x8uW3s?jnfhQ)Pg40KrHjtTSeR01NTVA`^6TC|1d-vMgOuG1h?Gv-d zXV-rL{@NA9Q$Fd@uH@7-p1fM@edC42fuYh`m`;lOZcqLDyARCzPA#3<_nV>5NiR=c zhI0-zak_~!m^+lf+29dJ&iGw?489S&0SI|<8Xj`Pj>U3qxvsisdd;*8ThsDneDjqH z_^2yi0$J;0ht>F}%T=`&9<<$?L~+O7O5b%_P$x4jLZ$`22tVR72IX{al#rX@FC*lq z;;Gn$%}e5e^KI)o+B+DPXu51B#fRaST|s>72fc%gtys8%wQ@RnA>M$`yPB^F=J+mrd4Lqii(15-8;YcstYTYrI5VI&eXpI*!G&& z-6aF)S~Ho%O*rR>_?Gv**>SSfUm0{C+>!^MoVersO5gQ{*-R#hCe9=)l%qF1kV59> z+ebvW3LSo3=1Y$Y(1kg98+IXTwWWIC&eW^#KF|fiU*g!~F23fy-_Egee0YmEv(tCF z#-30o(~IGcIqNUVy!f`fLf~}If=z#gk33pLk*B3I!aQ12YW2WLsx93;RN42BxZFKK zeEIubdJLW%mycUUc}M9b4>&RPUsu2H)yYJQa@E0)hE7QTy^cL*OXR0WKMYaAY<=Lt z+r2w3tkv*^_=l}*|AYmb6Y!olbLc_$+q(Vk^9QF_V;ZBlVK(`%$4W-0p_NXXOfCt( zIqG>dbh^|v_7H6Pz@w*5$X~{X1p2H_<=Xb7bMBymKAW9MIag-=%~(J`IXUCdaIktv zt5ik9R)o86YB7_US0DV^17E4MpTbR>D;g2shY!h2>*(y)a4JHVtRs{N>t=VB zF6wjRje~XjqCxyHoa}ph>rs@@ghWQiIMQ_&!yg^>%&Q0;Avf2}d&ui*!q#JTzyiF_>hy+&a2O_={80_Qzk6~ zq^l2}5!k$R0ybVhP9g+I5gV^(!Y6DL@WI%XBm~*gowYi(GZ9GfE9&@s8+vuLX^is9 z2p>{wGwVCc^n84IaylcM-m@KvQbPN zEkcM$czcIRwr@}1T<}O~(K64p=uS5wBglNEBjStR>+L;wTIb6epS9oO8*11+(G{!O z^hcKGLYY3fb^SMrfSYhG)3@VEd3^AVClIcnDi63mq-gvM!pY&F`55R9g zW`26qD*IlhPsP)ca&*);gKrjbHG;pc%I^#BdC7&6DL@E>{0E?YdLSZ%e5^yQn>;$Q zT8`;Hv*J7^?6!#Km0CXokLcCvV2r;QqdYvL$ZUqzZ1tTXL&{%I{xBonCNg(h-^m2O zaHZgF^X&*%qv}qR7sDqAA?1-hAh;Dm+?7H|g%2bDxMbcY;&UXWgqoyKBekUCFQ88x ztny20i5q467@7zdXwg)Ty*_r>ox#&UMz))cqo zW&v^O9^m5Z5Lf=gQ65)K3Vsxy;tJ-=J3m3hkC#jeeKh(htAl^VN8&8>iTSL%wT|tU zL7HY*w-o4wNLnfTE@N}`Ta?Yv#|F>MD6yFnX+yBN>Vfq8c@^QI_OpK%ZIGqYGIddO zb+l3**2~+c@=3V0f8eR<*Bq?sEjczyXb2=GQ5|&Kx^ZwhO_5v-e{|(HgJ%SJmcH-K_qFAZ#cK7{5oNa|c^ITbI>=6` z)jiqV=q^`4M#w~xab%#cLP`x=;c}9QTWtPy`-W+b=R?k0QpSO7 z0xb~*MUl4-wLNR77X5OlfbQ0*_BTWG3pZ?a-neQmw$G#StCyPq$ArJQ>akgfz$M#Y z6LWlK@;nHnO(AWb0+1hv=Q<+AT&A*KYbBISRhUdBhGEdeXYcF3&!K*$1NX`G=^^5W z$4qKyLZAR|;WF|b!e?ym0pW6j1)iS*o|iTyh)bvD6OR@!$vRI#OBsRC%1p^YMzI=G z7xCOq{>jBtpu>G;d3vnjG(D#0HZ04n*&_yxSrt6B8(21LC z>A$H?X0yZNP7_k8#Cx}6SN_Ne0OH}v)J0M7Z;o8czl~4djFlTzY!orap9Rkkd6xW? z7V(vlD4ocaXd#R;Q<`4<{kqc4BiobkD}5xHZV6sCOeee6Yc=Wnj%+%iD)2prA&)=b zkA^>H!%NN_v(5cA9^p{(H=6~7xTJ~@QVJfEJcbY;iI7p$tsP~(QlwIvnkj`0`e^4$ z#PgvqB`k*c72MPpr@O9u`u=+S@U5;`j!hS7oy10{OP_3nce(H!e;2s6iNCTTkGU<% zjS?;`G|3R-D3RFiCzivA_{EI!br-6$6wsfqy^E@|_id|RUi0B6XZ^+h#?ql>%8bpB zAdwLWKyVM?(-r-xV{Bdqj?{4USS@u$Yh=?hO(t9RR%=nZU#^_Bp|6TV9+ZpIc;*ak zW7WH8Y8J6x%Iyt1%U zjDKLGgmP+<4xe--ehKpyVX++Dusx9|QU)2pI38JjM8HPyYYV^OMead5bj(JZQMB2% z)=jk1o6kCXtC8SDu93fF<3cSq-n4xdEC&5`-l!E;Ku?au!?1-&LvR3Q~K zgp9bt>W8Z^b-ee!x)NgZZ2}Rpj^;aC76$|2U#G@rw^F_f53L#JYKEGjuNe+GKlHbo z^|!-xIQaHebDkoM*a+I1?7GjuzoJjkh>A=C6Nl10D)={!x4*ONC z%{VtIr&D|&ZcNVOIj*y&%<(z65x;`lu)sXH4ZCGniZ+tzzNbz&zu42O%5?Hve5GUb z{j_(~P36LTys-Z2p_|AIcP$6^*_pcYpc$i=f!5|(%3ox}n*>L9{=lF_+#j47Q?JcUyLHn3odoia&HjUrIP? zGVTAi@jdNee-OQlSS=2Q@9B0P9Bls4lRF6#G{3`cO9jeV|U|( z_%6Jkh!@2A070g{D`GPB`U?k2DbE;6cVWAXQNpC_;%^-zzW75Q<7%w-*XJ)}KcDYx zJHJ{RTexo=s8PNNPl4BU_kDPBMhT)k47a%sk`Ki%0Zw57vD|-!@Hx3lOj^=;m+Mu4%y$J5FvkLf zn^W5ExN*C8=iPS+p({mp-Q)15t{^`110Ux~Zp{6!9@g!dRWU>ubZ(kYy>U4>7#b0O zLjKLN%)V^DoRB3*i!9}tcsb6w7Pao;^F(|N<}yXrb6R~tW_hR{ANUwo^1vG=U%Nb5KYe{L7;FCNsQmVr@l_{hWj>j9-f&?M0qIUB zWWPmLDd;*P&f-V$8~FG4P{x+Q3gU}C;&HCVd{%ZhfAN3&hVhSfa(F_CbmPe_i{`GSht~&HZQ1VsDh0BK#BH(V^Li$?nxo zU3}q(KhCun7Rx^jp16*XiWAe0zIVsESH~(MG>9TgC)y}WPw9vNS|h^YXuJ5oPfG9N zYDbaLF|M5I(?h1CgP}RUs%8O1CWLDcpY>jka4qJumg_Y&)3~+07{>PR)bSm*r&IlO z>J4LOZ#l>S0vSa_$ml4AY?LB~B?3VNi&htGC}fs81bRejgS!`m`R5*+kzdvy-Mq`>og?nGJhdav^52 zn}=eo2zEva<96J44F`z^e>%yn5Mb_}{4%}SANG>px*d4^C%&?c?Yox;%P+uL z*xMUksMg1{XflhoHT|Tvtba4>22zC^5Z2aiZZNU1j6&Dr*?j0 zwl#Zc-*?Y;9mUsu+6TBd9qb*6r*8SIhOyn?ZL@?tElKydHn- iUKZc Date: Fri, 10 Nov 2023 21:53:07 +0000 Subject: [PATCH 2/8] temporarily disable cairo --- Cargo.lock | 1486 ++++++++++++++++++--- Cargo.toml | 4 +- projects/cas3-core/Cargo.toml | 2 +- projects/cas3-core/src/lib.rs | 2151 ++++++++++++++++++++++++++++++ projects/cas3-core/src/main.rs | 2135 +---------------------------- projects/cas3-jupyter/Cargo.toml | 8 +- 6 files changed, 3445 insertions(+), 2341 deletions(-) create mode 100644 projects/cas3-core/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c9cd8d8..110ae0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,144 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -21,35 +153,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] -name = "cairo-rs" -version = "0.18.2" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0466dfa8c0ee78deef390c274ad756801e0a6dbb86c5ef0924a298c5761c4d" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "bitflags 2.4.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror", + "generic-array", ] [[package]] -name = "cairo-sys-rs" -version = "0.18.2" +name = "bumpalo" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "bytemuck" +version = "1.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cas3" version = "0.1.0" dependencies = [ - "cairo-rs", "num-bigint", "num-traits", "ordered-float", @@ -57,6 +196,20 @@ dependencies = [ "rustyline", ] +[[package]] +name = "cas3-jupyter" +version = "0.0.0" +dependencies = [ + "async-trait", + "cas3", + "clap", + "jupyter", + "jupyter-derive", + "tokio", + "tracing-subscriber", + "url", +] + [[package]] name = "cc" version = "1.0.83" @@ -67,20 +220,65 @@ dependencies = [ ] [[package]] -name = "cfg-expr" -version = "0.15.5" +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ - "smallvec", - "target-lexicon", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.4", ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "clap" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clipboard-win" @@ -94,16 +292,156 @@ dependencies = [ ] [[package]] -name = "endian-type" -version = "0.1.2" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] -name = "equivalent" -version = "1.0.1" +name = "cpufeatures" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "errno" @@ -113,7 +451,7 @@ checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -136,6 +474,22 @@ dependencies = [ "str-buf", ] +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fd-lock" version = "3.0.13" @@ -144,7 +498,44 @@ checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", "rustix", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", ] [[package]] @@ -154,6 +545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -163,15 +555,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] -name = "futures-executor" -version = "0.3.28" +name = "futures-io" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" @@ -181,9 +568,15 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + [[package]] name = "futures-task" version = "0.3.28" @@ -197,82 +590,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] -name = "gio-sys" -version = "0.18.1" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", + "typenum", + "version_check", ] [[package]] -name = "glib" -version = "0.18.2" +name = "getrandom" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c316afb01ce8067c5eaab1fc4f2cd47dc21ce7b6296358605e2ffab23ccbd19" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ - "bitflags 2.4.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", + "cfg-if", "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror", + "wasi", ] [[package]] -name = "glib-macros" -version = "0.18.2" +name = "gif" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8da903822b136d42360518653fcf154455defc437d3e7a81475bf9a95ff1e47" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" dependencies = [ - "heck", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.37", + "color_quant", + "weezl", ] [[package]] -name = "glib-sys" -version = "0.18.1" +name = "gimli" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] -name = "gobject-sys" -version = "0.18.0" +name = "half" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" dependencies = [ - "glib-sys", - "libc", - "system-deps", + "cfg-if", + "crunchy", ] [[package]] @@ -287,30 +659,177 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] -name = "indexmap" -version = "2.0.2" +name = "iana-time-zone" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ - "equivalent", - "hashbrown", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jupyter" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "888cc24e404e8b3954919bccab69a5cce20b07310bea6657f0fe16a4fcafc518" +dependencies = [ + "bytes", + "chrono", + "clap", + "clap_derive", + "crossbeam-channel", + "dirs", + "generic-array", + "hex", + "hmac", + "serde", + "serde-lsp", + "serde_json", + "sha2", + "tokio", + "tracing", + "unicode-segmentation", + "uuid", + "zeromq", +] + +[[package]] +name = "jupyter-derive" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e92b0e2a3a5bc96fe628e6eb21939efb8beeb8528bde50c900cb5131baa21e" +dependencies = [ + "image", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.0", + "libc", + "redox_syscall", +] [[package]] name = "linux-raw-sys" @@ -318,6 +837,16 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -330,6 +859,27 @@ version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -350,6 +900,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -380,12 +940,37 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-float" version = "4.1.0" @@ -395,6 +980,35 @@ dependencies = [ "num-traits", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + [[package]] name = "peg" version = "0.8.1" @@ -422,6 +1036,12 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -435,73 +1055,166 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.27" +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] -name = "proc-macro-crate" -version = "1.3.1" +name = "rayon" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "either", + "rayon-core", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "rayon-core" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "crossbeam-deque", + "crossbeam-utils", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "redox_syscall" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "bitflags 1.3.2", ] [[package]] -name = "proc-macro2" -version = "1.0.67" +name = "redox_users" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "unicode-ident", + "getrandom", + "libredox", + "thiserror", ] [[package]] -name = "quote" -version = "1.0.33" +name = "regex" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ - "proc-macro2", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "radix_trie" -version = "0.2.1" +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ - "endian-type", - "nibble_vec", + "aho-corasick", + "memchr", + "regex-syntax", ] +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" version = "0.38.14" @@ -512,7 +1225,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -547,9 +1260,15 @@ checksum = "5a32af5427251d2e4be14fc151eabe18abb4a7aad5efee7044da9f096c906a43" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + [[package]] name = "scopeguard" version = "1.2.0" @@ -558,33 +1277,80 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-lsp" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bad35dfec920d3aa82b545b125c0a2a574c6a07aa673e3df9fddc4ed5a5444" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] -name = "serde_spanned" -version = "0.6.4" +name = "serde_json" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ + "itoa", + "ryu", "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -600,123 +1366,238 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "str-buf" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" -version = "1.0.109" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", + "quote", "unicode-ident", ] [[package]] -name = "syn" -version = "2.0.37" +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn", ] [[package]] -name = "system-deps" -version = "6.1.2" +name = "thread_local" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af52f9402f94aac4948a2518b43359be8d9ce6cd9efc1c4de3b2f7b7e897d6" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", ] [[package]] -name = "target-lexicon" -version = "0.12.12" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] [[package]] -name = "thiserror" -version = "1.0.50" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ - "thiserror-impl", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", ] [[package]] -name = "thiserror-impl" -version = "1.0.50" +name = "tokio-macros" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] -name = "toml" -version = "0.8.4" +name = "tokio-util" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef75d881185fd2df4a040793927c153d863651108a93c7e17a9e591baa95cc6" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.20.4", + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", ] [[package]] -name = "toml_datetime" -version = "0.6.5" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "serde", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "toml_edit" -version = "0.19.15" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "indexmap", - "toml_datetime", - "winnow", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "toml_edit" -version = "0.20.4" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380f9e8120405471f7c9ad1860a713ef5ece6a670c7eae39225e477340f32fc4" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.10.1" @@ -729,6 +1610,17 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.1" @@ -736,10 +1628,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] -name = "version-compare" -version = "0.1.1" +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" @@ -747,6 +1649,72 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "winapi" version = "0.3.9" @@ -769,13 +1737,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -784,13 +1770,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -799,36 +1800,72 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -836,10 +1873,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "winnow" -version = "0.5.17" +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zeromq" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "9ad3ffd65d6ae06a9eece312a64c3dfa2151a70a5c99051e2080828653cbda45" dependencies = [ - "memchr", + "async-trait", + "asynchronous-codec", + "bytes", + "crossbeam-queue", + "dashmap", + "futures-channel", + "futures-io", + "futures-task", + "futures-util", + "log", + "num-traits", + "once_cell", + "parking_lot", + "rand", + "regex", + "thiserror", + "tokio", + "tokio-util", + "uuid", +] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index 1b5a769..85a9e88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ resolver = "2" members = ["projects/*"] default-members = [ - "projects/valkyrie-interpreter", - "projects/valkyrie-jupyter", + "projects/cas3-core", + "projects/cas3-jupyter", ] exclude = [ "projects/playground", diff --git a/projects/cas3-core/Cargo.toml b/projects/cas3-core/Cargo.toml index bd4fc52..90fb288 100644 --- a/projects/cas3-core/Cargo.toml +++ b/projects/cas3-core/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cairo-rs = { version = "0.18.2", features = ["svg"] } +#cairo-rs = { version = "0.18.2", features = ["svg"] } num-bigint = "0.4.4" num-traits = "0.2.17" ordered-float = "4.1.0" diff --git a/projects/cas3-core/src/lib.rs b/projects/cas3-core/src/lib.rs new file mode 100644 index 0000000..2fe9661 --- /dev/null +++ b/projects/cas3-core/src/lib.rs @@ -0,0 +1,2151 @@ +// extern crate cairo; +extern crate peg; +use std::{ + borrow::Cow::{self, Borrowed, Owned}, + ops::{Add, Mul}, +}; + +use ordered_float::{self, NotNan}; +// use rug::Integer; +// use num_bigint::BigInt; +use num_traits::cast::ToPrimitive; + +// use cairo::{Context, SvgSurface}; +use rustyline::{ + config::Configurer, + error::ReadlineError, + highlight::{Highlighter, MatchingBracketHighlighter}, + validate::MatchingBracketValidator, + Completer, Editor, Helper, Hinter, Result, Validator, +}; + +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; +use std::time::{Duration, Instant}; +use std::{fmt, path::Path}; + +peg::parser! { + grammar expr_parser() for str { + rule comment() + = "(*" (!"*)" [_])* "*)" + + rule whitespace() = ([' ' | '\t' | '\n' | '\r'] / comment())* // Allow whitespace or comments + + rule integer() -> Expr + = n:$("-"? ['0'..='9']+ ) {? n.parse().map(Expr::Int).or(Err("integer")) } + + rule real() -> Expr + = n:$("-"? ['0'..='9']* "." ['0'..='9']* ) {? n.parse().map(Expr::Real).or(Err("real")) } + + rule symbol() -> Expr + = s:$(['a'..='z' | 'A'..='Z' | '?' | '$'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' ]* ) { Expr::Sym(s.into()) } + + rule string() -> Expr + = "\"" s:$((!['"'][_])* ) "\"" { Expr::Str(s.into()) } + + rule atom() -> Expr + = real() / integer() / symbol() / string() + + rule list() -> Expr + = "(" l:Expr() ** whitespace() ")" { Expr::List(l) } + + pub rule Expr() -> Expr + = whitespace() e:(atom() / list()) whitespace() { e } + + pub rule expressions() -> Vec + = whitespace() e:Expr() ** whitespace() { e } + } +} + +fn parse(s: &str) -> Expr { + expr_parser::Expr(s).unwrap() +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum Expr { + Int(num_bigint::BigInt), + // Int(Integer), + Real(ordered_float::NotNan), + Sym(String), + Str(String), + List(Vec), +} + +impl fmt::Display for Expr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Expr::Int(i) => write!(f, "{}", i), + Expr::Real(r) => write!(f, "{}", r), + Expr::Sym(s) => write!(f, "{}", s), + Expr::Str(s) => write!(f, "\"{}\"", s), + Expr::List(lst) => { + let str_list: Vec = lst.iter().map(|x| x.to_string()).collect(); + write!(f, "({})", str_list.join(" ")) + } + } + } +} + +impl Deref for Expr { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + match self { + Expr::List(vec) => vec, + e => panic!("Can only deref Expr::List. ex:{}", e), + } + } +} + +impl DerefMut for Expr { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Expr::List(vec) => vec, + _ => panic!("Can only deref Expr::List"), + } + } +} + +pub fn sym(s: &str) -> Expr { + Expr::Sym(s.to_string()) +} + +fn list(strs: Vec<&str>) -> Expr { + Expr::List(strs.iter().map(|s| sym(s)).collect::>()) +} + +fn liste(es: Vec) -> Expr { + Expr::List(es) +} + +fn head(expr: &Expr) -> Expr { + match expr { + Expr::Int(_) => Expr::Sym("Int".to_string()), + Expr::Real(_) => Expr::Sym("Real".to_string()), + Expr::Sym(_) => Expr::Sym("Sym".to_string()), + Expr::Str(_) => Expr::Sym("Str".to_string()), + Expr::List(lst) => { + if let Some(first) = lst.first() { + first.clone() + } else { + println!("[ERROR]: empty list isnt allowed"); + Expr::Sym("GET_FUCKED".to_string()) + } + } + } +} + +fn length(expr: &Expr) -> Expr { + match expr { + Expr::List(es) => Expr::Int((es.len() - 1).into()), + _ => Expr::Int(0.into()), + } +} + +// (a b c) -> (b c) +// fn rest(expr: &Expr) -> Expr {} + +pub fn is_atom(expr: &Expr) -> bool { + match expr { + Expr::List(_) => false, + _ => true, + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Context2 { + pub vars: HashMap, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct TableEntry { + own: Option, + down: Expr, + sub: Expr, +} + +impl TableEntry { + pub fn new() -> Self { + Self { + own: None, + down: Expr::List(vec![sym("List")]), + sub: Expr::List(vec![sym("List")]), + } + } +} + +pub fn get_ownvalue(ctx: &Context2, sym: Expr) -> Option { + // println!("ctx: {:?}. sym: {}", ctx, sym); + let te = ctx.vars.get(&sym); + if let Some(te) = te { + let rule = te.own.clone(); + return rule; + // for now, since I'm only allowing a single ownvalue maybe im not going to do the whole handling of HoldPattern[lhs] :> rhs + // where i actually take sym and do sym /. OwnValues[sym] + // apply_rule() + } else { + None + } +} + +/// i hate this function +fn unpack_mat(ex: Expr) -> Option>> { + let mut result: Vec> = vec![]; + + if let Expr::List(outer_list) = ex { + // println!("outerr elem: {:?}", outer_list[0]); + for outer_elem in &outer_list[1..] { + if let Expr::List(inner_list) = outer_elem { + let mut inner_vec: Vec<(f64, f64, f64)> = vec![]; + // println!("inner elem: {:?}", inner_list[0]); + for inner_elem in &inner_list[1..] { + if let Expr::List(tuple_list) = inner_elem { + // println!("tuple_list: {:?}", tuple_list); + if tuple_list.len() == 4 { + if let (Expr::Real(a), Expr::Real(b), Expr::Real(c)) = + (&tuple_list[1], &tuple_list[2], &tuple_list[3]) + { + inner_vec.push((a.into_inner(), b.into_inner(), c.into_inner())); + } else { + return None; // one of the elements was not a Real + } + } else { + return None; // tuple_list did not contain exactly 3 elements + } + } else { + return None; // inner_elem was not a List + } + } + result.push(inner_vec); + } else { + return None; // outer_elem was not a List + } + } + Some(result) + } else { + None // ex was not a List + } +} + +// fn create_svg_from_colors(colors: Vec>, filename: &str, scale_factor: i32) { +// let rows = colors.len(); +// let cols = colors[0].len(); // Assuming all rows have the same length +// +// let width = cols as i32 * scale_factor; +// let height = rows as i32 * scale_factor; +// +// // Create SvgSurface +// let surface = SvgSurface::new(width as f64, height as f64, Some(filename)) +// .expect("Couldn't create SVG surface"); +// +// // Create Context for drawing +// let cr = Context::new(&surface).expect("Couldn't create Cairo context"); +// +// // Scale the coordinate system +// cr.scale(scale_factor as f64, scale_factor as f64); +// +// // Loop through each cell to draw rectangles with specified colors +// for (i, row) in colors.iter().enumerate() { +// for (j, &(r, g, b)) in row.iter().enumerate() { +// cr.rectangle(j as f64, i as f64, 1.0, 1.0); +// cr.set_source_rgb(r, g, b); +// cr.fill().expect("Failed to fill rectangle"); +// } +// } +// +// // Finish drawing +// cr.show_page().expect("Failed to save SVG"); +// } + +// fn export() + +// are we guaranteed that we have a list here? +// can evaluated_args be empty +// nh can be List too +pub fn internal_functions_apply( + stack: &mut Expr, + ctx: &mut Context2, + nh: Expr, + evaluated_args: Vec, +) -> Expr { + let reconstructed_ex = Expr::List( + std::iter::once(nh.clone()) + .chain(evaluated_args.clone().to_owned()) + .collect(), + ); + + if nh == sym("matchq") { + if evaluated_args.len() != 2 { + println!("matchq takes 2 arguments"); + return sym("$Failed"); + } + return Expr::Sym(format!( + "{}", + my_match( + evaluated_args[0].clone(), + evaluated_args[1].clone(), + &vec![], + &mut HashMap::new(), + &mut HashMap::new() + ) + )); + } else if nh == sym("sameq") { + // println!("in sameq: evaluated_args: {:?}", evaluated_args); + let first_arg = &evaluated_args[0]; + let all_same = evaluated_args.iter().all(|arg| arg == first_arg); + return Expr::Sym(format!("{}", all_same)); + } else if nh == sym("replace") { + return replace(&evaluated_args[0], &evaluated_args[1]); + } else if nh == sym("replace_all") { + return replace_all(&evaluated_args[0], &evaluated_args[1]); + } else if nh == sym("rr") || nh == sym("replace_repeated") { + if evaluated_args.len() != 2 { + println!("replace_repeated takes 2 arguments"); + return sym("$Failed"); + } + return replace_repeated(&evaluated_args[0], &evaluated_args[1]); + } else if nh == sym("head") { + return head(&evaluated_args[0]); + } else if nh == sym("parse") { + match evaluated_args[0] { + Expr::Str(ref s) => { + let pex = expr_parser::Expr(s); + match pex { + Ok(expr) => return expr, + Err(err) => { + println!("Failed to parse: {}", err); + return sym("$Failed"); + } + } + } + _ => { + println!("parse takes a string"); + return sym("$Failed"); + } + } + } else if nh == sym("set") { + // array part setting notes: + // (set l (Table false 9)) + // simple single assignment case + // (set (Part l 1) 3) + + // this is the more advanced case setting multiple at the same time + // (set (Part l (list 1 2 3)) (Table true 3)) + + // println!("evaluated_args: {:?}", evaluated_args); + let lhs = &evaluated_args[0]; + let rhs = &evaluated_args[1]; + + match lhs { + // ownvalue + Expr::Sym(ref s) => { + // pretty sure this needs to be fixed to check if te already exists + let mut te = TableEntry::new(); + te.own = Some(evaluated_args[1].clone()); + ctx.vars.insert(sym(s), te); + return evaluated_args[1].clone(); + } + // this is the down/subvalue case + Expr::List(ls) => { + let lhs_h = &ls[0]; + match lhs_h { + // lhs_h is the tag in this downvalue assignment + Expr::Sym(_) => { + // todo: implementing list inplace modification + // if lhs_h == &sym("Part") { + // let part_lhs = &ls[1]; + // let part_rhs = &ls[2]; + // assert_eq!(length(rhs), length(part_rhs)); + // } + //given + // (set (f (pattern x (blank))) x) + // we end up pushing + // (rule_delayed (holdpattern expr[1]) expr[2]) + // (rule_delayed (holdpattern evaluated_args[0]) evaluated_args[1]) + // onto the downvalues of h (which is expected to have head list) + let te: &mut TableEntry = ctx + .vars + .entry(lhs_h.clone()) + .or_insert_with(TableEntry::new); + let dv_str = format!("(rule_delayed (hold_pattern {lhs}) {rhs})"); + let dv = expr_parser::Expr(&dv_str).unwrap(); + + // NOTE! here we aren't inserting in the right order, where we look for more specific + // definitions and insert them first. so user has to do the right order themselves + // at the moment + te.down.push(dv); + return rhs.clone(); + } + // subvalue + Expr::List(_) => { + todo!("subvalues") + } + _ => { + let h = head(lhs_h); + println!("Tag {h} in {lhs} is Protected"); + return rhs.clone(); + } + } + } + _ => { + println!("set takes a symbol or list, got {}", lhs); + return sym("$Failed"); + } + } + } else if nh == sym("setd") { + // println!("evaluated_args: {:?}", evaluated_args); + let lhs = &evaluated_args[0]; + match lhs { + Expr::Sym(ref s) => { + // pretty sure this needs to be fixed to check if te already exists + let mut te = TableEntry::new(); + te.own = Some(evaluated_args[1].clone()); + ctx.vars.insert(sym(s), te); + return sym("Null"); + } + // this is the down/subvalue case + Expr::List(ls) => { + let lhs_h = &ls[0]; + match lhs_h { + // lhs_h is the tag in this downvalue assignment + Expr::Sym(_) => { + let rhs = &evaluated_args[1]; + // onto the downvalues of h (which is expected to have head list) + let te: &mut TableEntry = ctx + .vars + .entry(lhs_h.clone()) + .or_insert_with(TableEntry::new); + let dv_str = format!("(rule_delayed (hold_pattern {lhs}) {rhs})"); + let dv = expr_parser::Expr(&dv_str).unwrap(); + + // NOTE! here we aren't inserting in the right order, where we look for more specific + // definitions and insert them first. so user has to do the right order themselves + // at the moment + te.down.push(dv); + return sym("Null"); + } + // subvalue + Expr::List(_) => { + todo!("subvalues") + } + _ => panic!("hi"), + } + } + _ => { + println!("set takes a symbol or list, got {}", lhs); + return sym("$Failed"); + } + } + } else if nh == sym("own_values") { + ctx.vars + .get(&evaluated_args[0]) + .unwrap() // there is a bug here + .own + .clone() + .unwrap() + // todo!() + } else if nh == sym("down_values") { + ctx.vars.get(&evaluated_args[0]).unwrap().down.clone() + } else if nh == sym("sub_values") { + todo!() + } else if nh == sym("clear") { + match &evaluated_args[0] { + Expr::Sym(_) => { + if let Some(te) = ctx.vars.get_mut(&evaluated_args[0]) { + te.own = None; + te.down = Expr::List(vec![sym("List")]); + te.sub = Expr::List(vec![sym("List")]); + } + return sym("Null"); + } + _ => { + println!("set takes a symbol"); + return sym("$Failed"); + } + } + } else if nh == sym("Plus") { + match (&evaluated_args[0], &evaluated_args[1]) { + (Expr::Int(a), Expr::Int(b)) => Expr::Int(a.add(b).into()), + // see issue about 3.0 printing as `3` + // (Expr::Real(a), Expr::Real(b)) => Expr::Real(a + b), + _ => { + let reconstructed_ex = Expr::List( + std::iter::once(nh.clone()) + .chain(evaluated_args.clone().to_owned()) + .collect(), + ); + return reconstructed_ex; + } + } + } else if nh == sym("Times") { + match (&evaluated_args[0], &evaluated_args[1]) { + (Expr::Int(a), Expr::Int(b)) => Expr::Int(a.mul(b).into()), + _ => { + return reconstructed_ex; + } + } + } else if nh == sym("Part") { + match &evaluated_args[0] { + Expr::List(ls) => match &evaluated_args[1] { + Expr::Int(i) => { + let i = i.to_isize().unwrap(); + if i < 0 || i >= ls.len() as isize { + println!("Part: index {} out of range", i); + return reconstructed_ex; + } + return ls[i as usize].clone(); + } + Expr::List(indices) => { + let mut results = vec![sym("List")]; + for index in indices[1..].iter() { + match index { + Expr::Int(i) => { + let i = i.to_isize().unwrap(); + if i < 0 || i >= ls.len() as isize { + println!("Part: index {} out of range", i); + return reconstructed_ex; + } + results.push(ls[i as usize].clone()); + } + _ => { + // println!("Part: each index in the list must be an integer"); + return reconstructed_ex; + } + } + } + return Expr::List(results); + } + _ => { + // println!("Part: index must be an integer or a list of integers"); + return reconstructed_ex; + } + }, + _ => return reconstructed_ex, + } + } else if nh == sym("Length") { + return length(&evaluated_args[0]); + } else if nh == sym("Get") { + if let Expr::Str(p) = &evaluated_args[0] { + let res = run_file(ctx, Path::new(&p)); + if let Ok(res) = res { + return res; + } else { + return sym("$Failed"); + } + } else { + println!("Get takes an Expr::String"); + return sym("$Failed"); + } + } else if nh == sym("Map") { + // todo level spec + // honestly i was hoping i could do this in cas3, not builtin but just to get things going + + let mut res = liste(vec![head(&evaluated_args[1])]); + let f = &evaluated_args[0]; + let mapargs = &evaluated_args[1]; + + for (_i, arg) in mapargs[1..].iter().enumerate() { + let fi = Expr::List(vec![f.clone(), arg.clone()]); + res.push(fi); + } + return res; + } else if nh == sym("NestList") { + let f = &evaluated_args[0]; + let x = &evaluated_args[1]; + let n = &evaluated_args[2]; + let mut res = list(vec!["List"]); + res.push(x.clone()); + if let Expr::Int(count) = n { + for _i in 0..count.to_i64().unwrap() { + let fi = evaluate( + stack, + ctx, + &Expr::List(vec![f.clone(), res.last().unwrap().clone()]), + ); + res.push(fi); + } + return res; + } else { + return reconstructed_ex; + } + } else if nh == sym("Table") { + let table_body = &evaluated_args[0]; + + // todo: test if this works implemented in cas3 code + if evaluated_args.len() == 1 { + return table_body.clone(); + } + let spec = evaluate(stack, ctx, &evaluated_args[1].clone()); + + if evaluated_args.len() == 2 { + // if int, we copy n times + if let Expr::Int(n) = &spec { + return Expr::List( + std::iter::once(sym("List")) + .chain((0..n.to_i64().unwrap()).map(|_| evaluated_args[0].clone())) + .collect(), + ); + } else if let Expr::List(ls) = &spec { + // this is the place where we want to make helpers for + // the "standard Wolfram Language iteration specification" + + let mut res = Expr::List(vec![sym("List")]); + let var = &ls[1]; + + // this specific case is {i, imax} + if ls.len() == 3 { + if ls[0] != sym("List") { + dbg!("invalid range specification. need a list"); + // return reconstructed_ex; + } + if let Expr::Int(imax) = &ls[2] { + for i in 1..=imax.to_i64().unwrap() { + let mut e_i = Expr::List(vec![sym("replace_all")]); + e_i.push(table_body.clone()); + let local_rule = + Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) + e_i.push(local_rule); + res.push(e_i); + } + return res; + } else if let Expr::List(vals) = &ls[2] { + // this is the sequence case where you just + // Table[expr,{i,{i1,i2,…}}] + + if head(&ls[2]) != sym("List") { + dbg!( + "invalid range specification. need a list of values, gave {}", + &ls[2] + ); + // return reconstructed_ex; + } else { + for val in &vals[1..] { + let mut e_i = Expr::List(vec![sym("replace_all")]); + e_i.push(table_body.clone()); + let local_rule = + Expr::List(vec![sym("rule"), var.clone(), val.clone()]); // (rule var iter) + e_i.push(local_rule); + res.push(e_i); + } + return res; + } + } else { + dbg!("need an int or list for imax, reals not supported in iteration specification yet"); + return sym("$Failed"); + } + } else if ls.len() == 4 { + // this is {i, imin, imax} + if let (Expr::Int(imin), Expr::Int(imax)) = (&ls[2], &ls[3]) { + for i in imin.to_i64().unwrap()..=imax.to_i64().unwrap() { + let mut e_i = Expr::List(vec![sym("replace_all")]); + e_i.push(table_body.clone()); + let local_rule = + Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) + e_i.push(local_rule); + res.push(e_i); + } + return res; + } else { + // this is the sequence case where you just + // Table[expr,{i,{i1,i2,…}}] + dbg!("need an int or list for imax, reals not supported in iteration specification yet"); + return sym("$Failed"); + } + } else if ls.len() == 5 { + // this is {i, imin, imax, di} + // this is {i, imin, imax} + if let [Expr::Int(imin), Expr::Int(imax), Expr::Int(di)] = &ls[2..] { + let rng = imin.to_i64().unwrap()..=imax.to_i64().unwrap(); + let iter = rng.step_by(di.to_i64().unwrap() as usize); + for i in iter { + let mut e_i = Expr::List(vec![sym("replace_all")]); + e_i.push(table_body.clone()); + let local_rule = + Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) + e_i.push(local_rule); + res.push(e_i); + } + return res; + } else { + // this is the sequence case where you just + // Table[expr,{i,{i1,i2,…}}] + dbg!("need an int or list for imax, reals not supported in iteration specification yet"); + return sym("$Failed"); + } + } + } + } + + let range_lists = &evaluated_args[1..]; //.clone().reverse(); + // Table[ f[i,j], {i, imin, imax}, {j, jmin, jmax}] + // Table[Table[f[i,j], {j, jmin, jmax}], {i, imin, imax}] + // let mut ex = Expr::List(vec![sym("Table")]); + // ex.push(table_body.clone()); + + let mut nested_table = table_body.clone(); + for range in range_lists.iter().rev() { + let mut new_table = Expr::List(vec![sym("Table"), nested_table.clone()]); + new_table = match &mut new_table { + Expr::List(ref mut v) => { + v.push(range.clone()); + new_table.clone() + } + _ => panic!("Unexpected expression type"), + }; + nested_table = new_table; + } + return nested_table; + } else if nh == sym("Join") { + if !matches!(&evaluated_args[0], Expr::List(ls)) { + println!("Join joins lists dummy!"); + return reconstructed_ex; + } + + let ha = head(&evaluated_args[0]); + + let mut res = vec![ha.clone()]; + for e in evaluated_args { + if ha != head(&e) { + println!("Join: heads of arguments are not all the same"); + return reconstructed_ex; + } + if let Expr::List(ls) = e { + res.append(&mut ls[1..].to_vec()); + } else { + //fix + return sym("Failed"); + } + } + return Expr::List(res); + } else if nh == sym("Timing") { + let t1 = Instant::now(); + let res = evaluate(stack, ctx, &evaluated_args[0]); + let dt = t1.elapsed(); // Capture the elapsed time + + // Convert duration to seconds + let elapsed_seconds = dt.as_secs() as f64 + dt.subsec_nanos() as f64 * 1e-9; + // NotNan + Expr::List(vec![ + sym("List"), + Expr::Real(NotNan::new(elapsed_seconds).unwrap()), + res, + ]) + } else if nh == sym("Export") { + let dst = &evaluated_args[0]; + let ex = &evaluated_args[1]; + // println!("ex: {:?}", ex); + let m = unpack_mat(ex.clone()).unwrap(); + let filename = match dst { + Expr::Str(s) => s, + _ => { + println!("Export: first argument must be a string"); + return sym("$Failed"); + } + }; + // create_svg_from_colors(m, filename, 50); + return sym("Null"); + } else { + return Expr::List( + std::iter::once(nh.clone()) + .chain(evaluated_args.clone().to_owned()) + .collect(), + ); + } +} + +pub fn evaluate(stack: &mut Expr, ctx: &mut Context2, expr: &Expr) -> Expr { + let mut ex = expr.clone(); + let mut last_ex = None; + + loop { + if Some(&ex) == last_ex.as_ref() { + // If the expression hasn't changed, break the loop. + break; + } + // println!("evaluating: {}", ex); + + last_ex = Some(ex.clone()); + + match &ex { + Expr::Int(_) | Expr::Real(_) | Expr::Str(_) => { + break; + } + Expr::Sym(ref s) => { + if let Some(rule) = get_ownvalue(ctx, sym(s)) { + ex = rule; + } else { + break; + } + } + Expr::List(ref ls) => { + let h; + if let Some(sh) = ls.first() { + h = sh; + } else { + println!("Expr::List needs a head"); + return sym("$Failed"); + } + // step 5 + let mut nh = evaluate(stack, ctx, h); + + // step 6 + // the use of a separate stack here is questionable + // also to note that when we use "contains" on it, we also do a comparison against the head ("List"), which is wrong + // but for practical purposes shouldn't cause a problem + + // the most important next step here is making sure that (attrs set) works correctly + // note that something here causes SO + + // a potential problem here is that nh is not necesarily an atom + // nh can be Expr::List + + // 3a (we might be able to just replace_all((attrs h) (down_values attrs))) + // nvm 3a is less easy to see that a match wastn found + + // println!("hi"); + + // 1. assume h::Sym + // 2. get dvs of attr + // 3. find a matching rule in dvs to (attrs h) + // if no matching rule found, return "(List)" + + let mut nh_attrs = Expr::List(vec![sym("List")]); + // #16 - this is what we need to speed up. ideally bypass the pattern matcher somehow + // we know/can assume we are looking up (attrs SYM) + if let Expr::Sym(_) = nh.clone() { + let te = ctx.vars.entry(sym("attrs")).or_insert_with(TableEntry::new); + // (down_values attrs) + let dvs = &te.down; + let attr_expr = + expr_parser::Expr(&format!("(attrs {})", nh).to_string()).unwrap(); + // println!("attr_expr: {}", attr_expr); + if let Expr::List(_ls) = dvs { + // dv expected to be (rule_delayed (hold_pattern lhs) rhs) + for dv in &_ls[1..] { + let mut pos_map = HashMap::new(); + let mut named_map = HashMap::new(); + let pos = vec![]; + if my_match( + attr_expr.clone(), + dv[1].clone(), + &pos, + &mut pos_map, + &mut named_map, + ) { + // println!("found attributes match for {} -> {}", nh, dv); + nh_attrs = replace(&attr_expr, dv); + break; // Exit the loop once a match is found + } + } + } else { + panic!("down_values must be a list"); + } + } + + // println!("nh_attrs: {:?}", nh_attrs); + // assert!(head(&nh_attrs) == sym("List")); + if nh_attrs.contains(&sym("HoldAllComplete")) { + // skip to 14 + todo!(); + } + + // step 7 + let mut evaluated_args = vec![]; + + // hold_mask entry with a zero means "don't hold" + let mut hold_mask = vec![false; ls.len() - 1]; + + // idk if it should be else ifs + if nh_attrs.contains(&sym("HoldAll")) { + hold_mask.fill(true); + } + if nh_attrs.contains(&sym("HoldFirst")) { + hold_mask[0] = true; + } + if nh_attrs.contains(&sym("HoldRest")) { + hold_mask[1..].fill(true); + } + // println!("hold_mask: {:?}", hold_mask); + + for (i, p) in ls[1..].iter().enumerate() { + if hold_mask[i] { + evaluated_args.push(p.clone()); + } else { + let ev = evaluate(stack, ctx, p); + + evaluated_args.push(ev); + } + } + + if !nh_attrs.contains(&sym("SequenceHold")) { + let mut arg_idx = 0; + while arg_idx < evaluated_args.len() { + if head(&evaluated_args[arg_idx]) == sym("Sequence") { + let seq_args: Vec<_> = evaluated_args[arg_idx][1..].to_vec(); + evaluated_args.splice(arg_idx..arg_idx + 1, seq_args); + } else { + arg_idx += 1; + } + } + } + let reconstructed_ex = Expr::List( + std::iter::once(nh.clone()) + .chain(evaluated_args.clone().to_owned()) + .collect(), + ); + // println!("reconstructed_ex: {}", reconstructed_ex); + + // step 14: apply user defined downvalues and subvalues + let exprime = match nh.clone() { + // we dont need to panic here "abc"[foo] doesn't + Expr::Int(_) | Expr::Real(_) | Expr::Str(_) => { + // note: WL doesn't give note in this case + println!("head must be a symbol, got {nh}"); + return reconstructed_ex; + } + // this is the down_value case, bcause the head + Expr::Sym(_) => { + let te = ctx.vars.entry(nh.clone()).or_insert_with(TableEntry::new); + let dvs = &te.down; + // println!("looking for user defined down_values for {} -> {}", nh, dvs); + + // should this be replace_all? or replace_repeated? + + let exprime = replace_all(&reconstructed_ex, dvs); + // println!("before: {}", reconstructed_ex); + // println!("after: {}", exprime); + exprime + } + // subvalue + Expr::List(_) => reconstructed_ex.clone(), + }; + + // im not sure if this is correct, but it seems necesary, + // if we found a matching downvalue rule, then we need to re-evaluate the expression after replacement + if ex != exprime { + ex = exprime; + continue; + } + + // note now that ex is not necesarily a List anymore + // so if we still have a list, then we do step 15, and apply internal down/subvalues + + match ex { + Expr::List(_) => {} + _ => continue, + } + nh = head(&ex); + evaluated_args = ex[1..].to_vec(); + // this corresponds to step 15 in Wagner's main eval loop section + // where we apply internal/builtin down and subvalues + ex = internal_functions_apply(stack, ctx, nh, evaluated_args); + } + } + } + // println!("exiting evaluate: {}", ex); + ex +} + +fn named_rebuild_all(expr: Expr, map: &HashMap) -> Expr { + // First, check if the entire expression exists in the map and replace it if it does + if let Some(replacement) = map.get(&expr) { + return replacement.clone(); + } + + // If the expression is not in the map, proceed with the recursion + match expr { + Expr::List(list) => { + // Recursively rebuild all sub-expressions in the list + let new_list: Vec = list + .into_iter() + .map(|e| named_rebuild_all(e, map)) + .collect(); + Expr::List(new_list) + } + _ => expr, + } +} + +// this adjusts lookups to the position map based on the sequences found in the current list +fn final_pos_map_rebuild(pos: Vec, pat: Expr, pos_map: &HashMap, Expr>) -> Expr { + // println!("pos: {:?}, pat: {}", pos, pat); + if let Some(replacement) = pos_map.get(&pos) { + return replacement.clone(); + } + + match pat { + Expr::List(es) => { + let mut new_es = vec![]; + // note in the case of blank_null_seq, this can be negative + let mut offset: isize = 0; + for (i, e) in es.iter().enumerate() { + let mut new_pos = pos.clone(); + let pos_in_list = i as isize + offset; + // println!("{i}, pos_in_list: {} offset:{offset}", pos_in_list); + new_pos.push(pos_in_list as usize); + let new_e = final_pos_map_rebuild(new_pos, e.clone(), pos_map); + if head(&new_e) == sym("Sequence") { + offset += new_e.len() as isize - 2; // its -2 becasue 1 for the head and 1 for the original (blank_seq) object + } + // so pos[0..i-1] is the position of the current list + // we want to then look for all the position keys that have thsi as a prefix and adjust them + // but i think we only want to adjust on a final rebuild but not in the middle. + // when we are at the end of a list we are confirming the map works but haven't rebuilt anything, so our pat is still the original + // println!("{i}, new_e: {} offest: {offset}", new_e); + new_es.push(new_e); + } + Expr::List(new_es) + } + _ => pat, + } +} + +/// to fix pos_map. as you iterate es, and you keep track of the offset for the current list. +/// then you want to adjust lookups into the posmap based on the position - offset. +/// the reason we still need this is for intermediate rebuilds where we have already spliced former sequences +fn pos_map_rebuild(pos: Vec, pat: Expr, pos_map: &HashMap, Expr>) -> Expr { + if let Some(replacement) = pos_map.get(&pos) { + return replacement.clone(); + } + + match pat { + Expr::List(es) => { + let mut new_es = vec![]; + // note in the case of blank_null_seq, this can be negative + for (i, e) in es.iter().enumerate() { + let mut new_pos = pos.clone(); + new_pos.push(i); + let new_e = pos_map_rebuild(new_pos, e.clone(), pos_map); + new_es.push(new_e); + } + Expr::List(new_es) + } + _ => pat, + } +} + +fn splice_sequences(expr: Expr) -> Expr { + match expr { + Expr::List(mut list) => { + let mut i = 0; + while i < list.len() { + list[i] = splice_sequences(list[i].clone()); + i += 1; + } + + let mut new_list = Vec::new(); + let mut i = 0; + while i < list.len() { + let item = list[i].clone(); + if let Expr::List(ref sublist) = item { + if let Some(Expr::Sym(head)) = sublist.first() { + if head == "Sequence" { + new_list.extend_from_slice(&sublist[1..]); + i += 1; + continue; + } + } + } + new_list.push(item); + i += 1; + } + Expr::List(new_list) + } + _ => expr, + } +} + +fn rebuild_and_splice( + pat: Expr, + pos: &Vec, + pos_map: &HashMap, Expr>, + named_map: &HashMap, +) -> Expr { + splice_sequences(named_rebuild_all( + pos_map_rebuild(pos.clone(), pat, pos_map), + named_map, + )) +} + +fn final_rebuild_and_splice( + pat: Expr, + pos: &Vec, + pos_map: &HashMap, Expr>, + named_map: &HashMap, +) -> Expr { + splice_sequences(named_rebuild_all( + final_pos_map_rebuild(pos.clone(), pat, pos_map), + named_map, + )) +} + +// we assume that p has a blank object for a head +fn is_blank_match(e: Expr, p: Expr) -> bool { + if let Expr::List(ps) = p { + if ps.len() == 2 { + let p_head = &ps[1]; + if p_head == &head(&e) { + true + } else { + false + } + } else { + true + } + } else { + panic!("is_blank_match needs a list for p") + } +} + +fn my_match( + ex: Expr, + mut pat: Expr, + pos: &Vec, + pos_map: &mut HashMap, Expr>, + named_map: &mut HashMap, +) -> bool { + let pattern_expr = pat.clone(); + if head(&pattern_expr) == sym("hold_pattern") { + pat = pattern_expr[1].clone(); + } + // if head(&pat) != sym("attrs") && pat != sym("attrs") && ex != sym("matchq") { + // println!("M: {pos:?} | {ex} | {pat} | {pos_map:?} | {named_map:?}"); + // } + + let pat_syms = vec![sym("blank"), sym("blank_seq"), sym("blank_null_seq")]; + if head(&pat) == sym("Alternatives") { + for p in &pat[1..] { + if my_match(ex.clone(), p.clone(), pos, pos_map, named_map) { + pos_map.insert(pos.clone(), p.clone()); + return true; + } + } + return false; + } + + match (ex.clone(), pat.clone()) { + (Expr::List(es), Expr::List(ps)) => { + // this first block determines if the pattern matches the entire list + if ps[0] == sym("pattern") { + if let Some(from_map) = named_map.get(&pat) { + return &ex == from_map; + } else { + if is_blank_match(ex.clone(), ps[2].clone()) { + named_map.insert(pat.clone(), ex.clone()); + return true; + } + } + } else if pat_syms.contains(&ps[0]) { + if is_blank_match(ex.clone(), pat.clone()) { + pos_map.insert(pos.clone(), ex); + return true; + } + } + + let mut new_pos = pos.clone(); + new_pos.push(0); // we are at the head + if !my_match(es[0].clone(), ps[0].clone(), &new_pos, pos_map, named_map) { + return false; + } + + 'outer: for (i, pi) in ps.iter().enumerate().skip(1) { + let mut new_pos = pos.clone(); + new_pos.push(i); // we are at the head + if head(pi) == sym("pattern") { + // println!("in pattern pi "); + if let Some(_from_map) = named_map.get(&pi) { + // here is an example that contradicts the below i think + // (setd (Times (pattern x (blank Sym)) (pattern x (blank Sym))) (Pow x 2)) + println!("we should have rebuilt to remove this i think"); + } + let b = &pi[2]; + let bt = &b[0]; + // let p_name = &pi[1]; + if bt == &sym("blank_seq") { + for j in 1..=es[1..].len() { + let mut elts = vec![sym("Sequence")]; + // im pretty sure this is not needed + if i + j > es.len() { + // println!("breaking news!"); + break 'outer; + } + for seq_e in &es[i..i + j] { + if b.len() == 2 { + let b_head = &b[1]; + if b_head != &head(seq_e) { + break; + } + } + elts.push(seq_e.clone()); + } + let seq = liste(elts); + named_map.insert(pi.clone(), seq.clone()); + + let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + // println!("new_pat in bs: at iter {j} {new_pat} {seq}"); + if my_match(ex.clone(), new_pat, pos, pos_map, named_map) { + break 'outer; + } + } + } else if bt == &sym("blank_null_seq") { + for j in 0..=es[1..].len() { + let mut elts = vec![sym("Sequence")]; + // im pretty sure this is not needed + if i + j > es.len() { + // println!("breaking news!"); + break 'outer; + } + for seq_e in &es[i..i + j] { + if b.len() == 2 { + let b_head = &b[1]; + if b_head != &head(seq_e) { + break; + } + } + elts.push(seq_e.clone()); + } + let seq = liste(elts); + named_map.insert(pi.clone(), seq.clone()); + + let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + // println!("new_pat in bs: at iter {j} {new_pat} {seq}"); + if my_match(ex.clone(), new_pat, pos, pos_map, named_map) { + break 'outer; + } + } + } else { + if i >= es.len() { + break 'outer; + } + // named blank case + if !my_match(es[i].clone(), ps[i].clone(), &new_pos, pos_map, named_map) { + break 'outer; + } + } + } else if head(pi) == sym("blank_seq") { + for j in 1..=es[1..].len() { + let mut elts = vec![sym("Sequence")]; + // im pretty sure this is not needed + if i + j > es.len() { + // println!("breaking news!"); + break 'outer; + } + for seq_e in &es[i..i + j] { + if pi.len() == 2 { + let b_head = &pi[1]; + if b_head != &head(seq_e) { + break; + } + } + elts.push(seq_e.clone()); + } + let seq = liste(elts); + pos_map.insert(new_pos.clone(), seq.clone()); + + let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + // println!("new_pat in bs: at iter {j} {new_pat}"); + let mut copy = pos_map.clone(); + // this is to avoid double application of a pos rule + copy.remove(&new_pos); + // if my_match(ex.clone(), pat.clone(), pos, &mut copy) { + if my_match(ex.clone(), new_pat, pos, &mut copy, named_map) { + pos_map.clear(); + pos_map.extend(copy); + + pos_map.insert(new_pos.clone(), seq.clone()); + + break 'outer; + } else { + // break 'outer; + // i think we need to revert pos_map to whatever it was before this my_match call + } + } + } else if head(pi) == sym("blank_null_seq") { + for j in 0..=es[1..].len() { + let mut elts = vec![sym("Sequence")]; + // im pretty sure this is not needed + if i + j > es.len() { + println!("breaking news!"); + break 'outer; + } + for seq_e in &es[i..i + j] { + if pi.len() == 2 { + let b_head = &pi[1]; + if b_head != &head(seq_e) { + break; + } + } + elts.push(seq_e.clone()); + } + let seq = liste(elts); + pos_map.insert(new_pos.clone(), seq.clone()); + + let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + // println!("new_pat in bs: at iter {j} {new_pat}"); + let mut copy = pos_map.clone(); + // this is to avoid double application of a pos rule + copy.remove(&new_pos); + // if my_match(ex.clone(), pat.clone(), pos, &mut copy) { + if my_match(ex.clone(), new_pat, pos, &mut copy, named_map) { + pos_map.clear(); + pos_map.extend(copy); + + pos_map.insert(new_pos.clone(), seq.clone()); + + break 'outer; + } else { + // break 'outer; + // i think we need to revert pos_map to whatever it was before this my_match call + } + } + } else { + if i >= es.len() { + break 'outer; + } + if !my_match(es[i].clone(), ps[i].clone(), &new_pos, pos_map, named_map) { + break 'outer; + } + } + } + let final_pat = final_rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + // let final_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); + + // todo remove these conditions when we fast path attribute lookup + // if head(&pat) != sym("attrs") && pat != sym("attrs") { + // println!("final comparison: POS: {pos:?} | PAT: {pat} | NEW_PAT: {final_pat} | EX: {ex} || pos {pos_map:?} || named {named_map:?}"); + // } + if final_pat == ex { + return true; + } + false + } + (_, Expr::List(ps)) => { + if ps[0] == sym("pattern") { + if let Some(from_map) = named_map.get(&pat) { + return &ex == from_map; + } else { + if is_blank_match(ex.clone(), ps[2].clone()) { + named_map.insert(pat.clone(), ex.clone()); + true + } else { + false + } + } + } else if pat_syms.contains(&ps[0]) { + if is_blank_match(ex.clone(), pat.clone()) { + pos_map.insert(pos.clone(), ex); + true + } else { + false + } + } else { + false + } + } + _ => ex == pat, + } +} + +pub fn bindings_to_rules(bindings: &HashMap) -> Expr { + let mut rules = Expr::List(vec![sym("List")]); + for (name, binding) in bindings.clone() { + rules.push(Expr::List(vec![sym("rule"), sym(&name), binding.clone()])); + } + rules +} + +pub fn pat_bindings_to_rules(bindings: &HashMap) -> Expr { + let mut rules = Expr::List(vec![sym("List")]); + for (pat, binding) in bindings.clone() { + if let Expr::List(ps) = pat { + let p_name = &ps[1]; // (pattern x (blank)) + rules.push(Expr::List(vec![ + sym("rule"), + p_name.clone(), + binding.clone(), + ])); + } + } + rules +} + +pub fn norm_rules(rules: &Expr) -> Vec { + if head(rules) == sym("rule") || head(rules) == sym("rule_delayed") { + return vec![rules.clone()]; + } else { + assert_eq!(head(rules), sym("List")); + return rules.clone()[1..].to_vec(); + }; +} + +pub fn replace(expr: &Expr, rules: &Expr) -> Expr { + let rules_list = norm_rules(rules); + + for rule in rules_list { + let pos = vec![]; + let mut pos_map = HashMap::new(); + let mut named_map = HashMap::new(); + assert!(head(&rule) == sym("rule") || head(&rule) == sym("rule_delayed")); + if my_match( + expr.clone(), + rule[1].clone(), + &pos, + &mut pos_map, + &mut named_map, + ) { + let mut new_expr = rule[2].clone(); + new_expr = replace_all(&new_expr, &pat_bindings_to_rules(&named_map)); + + return new_expr; + } + } + expr.clone() +} + +pub fn replace_all(expr: &Expr, rules: &Expr) -> Expr { + let rules_list = norm_rules(rules); + for rule in rules_list { + let pos = vec![]; + let mut pos_map = HashMap::new(); + let mut named_map = HashMap::new(); + assert!(head(&rule) == sym("rule") || head(&rule) == sym("rule_delayed")); + if my_match( + expr.clone(), + rule[1].clone(), + &pos, + &mut pos_map, + &mut named_map, + ) { + return replace(expr, &rule); + } + } + + match expr { + Expr::List(list) => { + let new_list: Vec = list + .iter() + .map(|sub_expr| replace_all(sub_expr, rules)) + .collect(); + Expr::List(new_list) + } + _ => replace(expr, rules), + } +} + +pub fn replace_repeated(expr: &Expr, rules: &Expr) -> Expr { + let mut current_expr = expr.clone(); + let mut i = 0; + loop { + let new_expr = replace_all(¤t_expr, rules); + if new_expr == current_expr { + break; + } + current_expr = new_expr; + i += 1; + if i > 1 << 16 { + println!("replace_repeated, iteration limit 1<<16 reached"); + break; + } + } + current_expr +} + +pub fn startup_attrs(ctx: &mut Context2) { + let attrs_te = ctx.vars.entry(sym("attrs")).or_insert_with(TableEntry::new); + let mut exs = vec![ + format!("(rule_delayed (hold_pattern (attrs hold_pattern)) (list HoldAll))"), + format!("(rule_delayed (hold_pattern (attrs attrs)) (list HoldAll))"), + format!("(rule_delayed (hold_pattern (attrs rule_delayed)) (list HoldRest SequenceHold))"), + format!("(rule_delayed (hold_pattern (attrs set)) (list HoldFirst SequenceHold))"), + format!("(rule_delayed (hold_pattern (attrs down_values)) (list HoldAll))"), + ] + .iter_mut() + .map(|s| expr_parser::Expr(&s).unwrap()) + .collect(); + attrs_te.down.append(&mut exs); +} + +#[derive(Helper, Completer, Hinter, Validator)] +pub struct ReplHelper { + pub highlighter: MatchingBracketHighlighter, + #[rustyline(Validator)] + pub validator: MatchingBracketValidator, + pub colored_prompt: String, +} + +impl Highlighter for ReplHelper { + fn highlight_prompt<'b, 's: 'b, 'p: 'b>( + &'s self, + prompt: &'p str, + default: bool, + ) -> Cow<'b, str> { + if default { + Borrowed(&self.colored_prompt) + } else { + Borrowed(prompt) + } + } + + fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { + Owned("\x1b[1m".to_owned() + hint + "\x1b[m") + } + + fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { + self.highlighter.highlight(line, pos) + } + + fn highlight_char(&self, line: &str, pos: usize) -> bool { + self.highlighter.highlight_char(line, pos) + } +} + +pub fn run_file(ctx: &mut Context2, filepath: &Path) -> Result { + // let file = File::open(filepath)?; + // let reader = BufReader::new(file); + let file_contents = std::fs::read_to_string(filepath)?; + // i dont love this because it's ambigious whether or not something failed in reading the file or sth + // or if the last expr in the file was a setd or something that returns a Null + println!("Running file: {}", filepath.display()); + let mut res = sym("Null"); + let exprs = expr_parser::expressions(&file_contents).unwrap(); + // for line in reader.lines() { + for expr in exprs { + // match line { + // Ok(content) => { + // if content.starts_with("//") || content.starts_with(";") || content.is_empty() { + // continue; + // } + // if let Ok(ex) = &expr_parser::Expr(&content) { + let mut stack = Expr::List(vec![]); + res = evaluate(&mut stack, ctx, &expr); + // } else { + // eprintln!("Error parsing a line: {:?}", content); + // } + } + // Err(error) => { + // eprintln!("Error reading a line: {:?}", error); + // } + // } + // } + + Ok(res) +} + +pub fn run( + mut rl: rustyline::Editor, + mut ctx: Context2, +) -> Result<()> { + let mut i = 1; + + loop { + let prompt = format!("(In {}) := ", i); + rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{prompt}\x1b[0m"); + + let line = rl.readline(&prompt); // read + match line { + Ok(l) => { + rl.add_history_entry(l.as_str()).unwrap(); // history + // saving every line (even if slow, just until its more stable) + rl.save_history("history.txt").unwrap(); + + let exs = expr_parser::expressions(&l); + + match exs { + Ok(exprs) => { + for expr in exprs { + let mut stack = Expr::List(vec![]); + let res = evaluate(&mut stack, &mut ctx, &expr); + let in_i = + expr_parser::Expr(format!("(setd (In {i}) {})", expr).as_str()) + .unwrap(); + evaluate(&mut stack, &mut ctx, &in_i); + let out_i = + expr_parser::Expr(format!("(set (Out {i}) {})", res).as_str()) + .unwrap(); + evaluate(&mut stack, &mut ctx, &out_i); + + println!("\x1B[1m(Out {i}) = {}\x1B[0m", res); + + i += 1; + } + } + + Err(err) => println!("Failed to parse: {}", err), + } + } + Err(ReadlineError::Interrupted) => { + continue; + } + Err(ReadlineError::Eof) => { + break; + } + Err(err) => { + println!("Error: {:?}", err); + } + } + } // loop + Ok(()) +} + +fn main() -> Result<()> { + let h = ReplHelper { + highlighter: MatchingBracketHighlighter::new(), + colored_prompt: "".to_owned(), + validator: MatchingBracketValidator::new(), + }; + let config = rustyline::Config::default(); + let mut rl = Editor::with_config(config)?; + rl.set_max_history_size(10000).unwrap(); + rl.set_helper(Some(h)); + if rl.load_history("history.txt").is_err() { + println!("No previous history."); + } + let mut ctx = Context2 { + vars: HashMap::new(), + }; + + startup_attrs(&mut ctx); + run_file(&mut ctx, Path::new("lang/attrs.sexp"))?; + run_file(&mut ctx, Path::new("lang/startup.sexp"))?; + run_file(&mut ctx, Path::new("lang/calculus.sexp"))?; + // run_file(&mut ctx, Path::new("lang/systems.sexp"))?; + + run(rl, ctx)?; + Ok(()) +} + +pub fn evalparse(s: &str) -> Expr { + let ex = expr_parser::Expr(s); + match ex { + Ok(expr) => { + let mut ctx = Context2 { + vars: HashMap::new(), + }; + let mut stack = Expr::List(vec![]); + evaluate(&mut stack, &mut ctx, &expr) + } + Err(err) => panic!("Failed to parse: {s}: {err}"), + } +} + +pub fn ctx_evalparse(ctx: &mut Context2, s: &str) -> Expr { + let ex = expr_parser::Expr(s); + match ex { + Ok(expr) => { + let mut stack = Expr::List(vec![]); + evaluate(&mut stack, ctx, &expr) + } + Err(err) => panic!("Failed to parse: {s}: {err}"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parser() { + assert_eq!(parse("(f (* *hi* *) x)"), parse("(f x)")); + } + + #[test] + fn test_pattern_matching() { + assert_eq!(evalparse("(matchq 1 (blank))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (blank Int))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (pattern x (blank)))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (pattern x (blank Int)))"), sym("true")); + assert_eq!( + evalparse("(matchq 1 (pattern x (blank Sym)))"), + sym("false") + ); + assert_eq!( + evalparse("(matchq ((k a) b) ((k (pattern x (blank Sym))) (pattern y (blank Sym))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq ((k a) b) ((k (pattern x (blank))) (pattern y (blank))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq (plus 1 2) (plus (blank) (blank)))"), + sym("true") + ); + + assert_eq!(evalparse("(matchq (list a b c) (blank))"), sym("true")); + assert_eq!( + evalparse("(matchq (list a b c) (pattern x (blank)))"), + sym("true") + ); + + assert_eq!(evalparse("(matchq (f (g 1)) (f (g (blank))))"), sym("true")); + + // testing that patterns with the same name must equal the same matched expr + assert_eq!( + evalparse("(matchq (f a a) (f (pattern x (blank)) (pattern x (blank))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq (f a b) (f (pattern x (blank)) (pattern x (blank))))"), + sym("false") + ); + + // nested patterns, head is pattern + assert_eq!( + evalparse("(matchq (foo x) ((pattern f (blank)) (pattern y (blank))))"), + sym("true") + ); + + // head matching + assert_eq!( + evalparse("(matchq (list x) (pattern x (blank list)))"), + sym("true") + ); + + // blank doesnt match the here, which is correct. triple_blank would match this + assert_eq!(evalparse("(matchq (f) (f (blank)))"), sym("false")); + } + + #[test] + fn test_rules_and_replacement() { + assert_eq!( + evalparse("(replace ((k a) b) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"), + sym("a") + ); + + // list of rules does first one that matches + assert_eq!( + evalparse("(replace x (List (rule a b) (rule x y)))"), + sym("y") + ); + assert_eq!( + evalparse("(replace x (List (rule x y) (rule x z)))"), + sym("y") + ); + + // doesn't keep going + assert_eq!( + evalparse("(replace x (List (rule x y) (rule y z)))"), + sym("y") + ); + + // case where no rules apply + assert_eq!( + evalparse("(replace_all x (List (rule y a) (rule z b)))"), + sym("x") + ); + + // test for blank with head + nested List + assert_eq!( + evalparse(r#"(replace_all (List 1 1.5 Pi (List a 2)) (rule (blank Int) "hi"))"#), + expr_parser::Expr(r#"(List "hi" 1.5 Pi (List a "hi"))"#).unwrap() + ); + + assert_eq!( + evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1)))"), + expr_parser::Expr("(List 1 (power 1 2) y z)").unwrap() + ); + + assert_eq!( + evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1) (rule y 2)))"), + expr_parser::Expr("(List 1 (power 1 2) 2 z)").unwrap() + ); + + assert_eq!( + evalparse("(replace_all (plus 1 (pow x 2) (pow x 4)) (rule (pow x (pattern p (blank))) (f p)))"), + expr_parser::Expr("(plus 1 (f 2) (f 4))").unwrap() + ); + + let s = "(replace_repeated (List (f (f x)) (f x) (g (f x)) (f (g (f x)))) (List (rule (f (pattern x (blank))) x)))"; + // todo test s above to give (List x x (g x) (g x)) + assert_eq!( + evalparse(s), + expr_parser::Expr("(List x x (g x) (g x))").unwrap() + ); + // (s k) is false, and k is true + // Combinator reduction of And for Tuples[{True, False}] + // in boolean logic, you need 3 things to "do everything" + // true, false, nand + // whats cool about combinators, is you only need 2 things + // s and k combinators. everything else is up to interpretation + + let test_cases = vec![ + ("((((s s) k) (s k)) (s k))", "(s k)"), + ("((((s s) k) (s k)) k)", "(s k)"), + ("((((s s) k) k) (s k))", "(s k)"), + ("((((s s) k) k) k)", "k"), + ]; + let crules_str = "(List (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"; + for (input, res) in test_cases.iter() { + assert_eq!( + evalparse(&format!("(rr {} {crules_str})", input)), + expr_parser::Expr(res).unwrap() + ); + } + + // let nand = "s[ s[ k[ s[ s[ s][s[k[k[k]]]]]]]][s]"; + // (s (s (k (s (s s) (s (k (k k))))))) + + // let nand = "(((s s) (s (k (k k)))) s)"; + // let nand = "(((s s) (s (k (k k)))) s)"; + // let nand = "(s (s (k (s (((s s) (s (k (k k)))))))) s)"; + // let nand = "(((s (s (k (((s (s s)) (s (k (k k)))))))) s)"; + // let a = "k"; + // let b = "k"; + // let s = format!("(({nand} {a}) {b})"); + // println!("{}", s); + } + + #[test] + fn list_ops() { + assert_eq!( + evalparse("(sameq (Part (f x y z) (List 1 2 3)) (List x y z))"), + sym("true") + ); + } + + #[test] + fn seqs_and_geeks() { + assert_eq!( + evalparse("(sameq (f (Sequence a b) c (Sequence d e)) (f a b c d e))"), + sym("true") + ); + + let mut ctx = Context2 { + vars: HashMap::new(), + }; + run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + ctx_evalparse( + &mut ctx, + "(setd (listq (pattern x (blank))) (sameq list (head x)))", + ); + println!("listq ctx {:?}", ctx); + assert_eq!(ctx_evalparse(&mut ctx, "(listq (list a b c))"), sym("true")); + + run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + // issue #2 + assert_eq!( + ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), + sym("true") + ) + } + + #[test] + fn new_pattern_matcher() { + let blank = list(vec!["blank"]); + + let lhs = list(vec!["f", "a", "b"]); + let rhs = list(vec!["f", "blank"]); + + let test_cases = vec![ + (sym("1"), sym("1"), true), // goes to "1" == "1" Sym, Sym arm + (sym("1"), blank.clone(), true), // Sym Sym arm with blank + (sym("1"), Expr::List(vec![sym("1")]), false), // Sym List -> false + (Expr::List(vec![sym("1")]), sym("1"), false), // List Sym + // (1) | (blank) + (Expr::List(vec![sym("1")]), blank.clone(), true), // List, sym, with blank + (lhs.clone(), rhs.clone(), false), // List, sym, with blank + // (lhs.clone(), list(vec!["f", "blank", "blank"]), true), // List, sym, with blank + ( + lhs.clone(), + liste(vec![sym("f"), blank.clone(), blank.clone()]), + true, + ), // List, sym, with blank + (sym("f"), list(vec!["blank", "Sym"]), true), + (sym("f"), list(vec!["blank", "f"]), false), + (list(vec!["f", "x"]), list(vec!["blank", "f"]), true), + (list(vec!["f", "x"]), list(vec!["blank", "g"]), false), + (parse("(f (a b))"), parse("(f (blank))"), true), + (parse("(f (a b))"), parse("(f (blank a))"), true), + (parse("(f x)"), parse("((blank) (blank))"), true), + (parse("f"), parse("(pattern x (blank))"), true), + (parse("(f)"), parse("(pattern x (blank))"), true), + (parse("(f x)"), parse("((pattern x (blank)) (blank))"), true), + ( + parse("(f a b c)"), + parse("(f (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a b c)"), + parse("(f (pattern x (blank_seq)) (pattern y (blank_seq)))"), + true, + ), + ( + parse("(f a a)"), + parse("(f (pattern x (blank_seq)) (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a (g b))"), + parse("(f (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a)"), + parse("(f (pattern x (blank_null_seq)))"), + true, + ), + ( + parse("(f a)"), + parse("(f (pattern x (blank_null_seq)) a)"), + true, + ), + ( + parse("(f a b c a b)"), + parse("(f (pattern x (blank_seq)) c (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f (a b) c a b)"), + parse("(f (pattern x (blank b)) (pattern y (blank_seq)))"), + false, + ), + ( + parse("(f (a b) c a b)"), + parse("(f (pattern x (blank a)) (pattern y (blank_seq)))"), + true, + ), + ( + parse("(f a b c d)"), + parse("(f (blank_seq) (pattern y (blank_seq)))"), + true, + ), + // fails todo fix blank_seq with head + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (pattern x (blank_seq a)))"), + false, + ), + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (pattern x (blank_seq a)) (b d))"), + true, + ), + // pos : Vec where are we in the pattern Expr + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (blank_seq a) (b d))"), + true, + ), + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (blank_seq a))"), + false, + ), + ]; + + // list(vec!["f", "a", "b", "c"]), list(vec!["f", sym("blank_sequence")]) + for (i, (ex, pat, expected)) in test_cases.iter().enumerate() { + println!("testing case {i}: {ex} | {pat} "); + let pos = vec![]; + let mut pos_map = HashMap::new(); + let mut named_map = HashMap::new(); + let m = my_match(ex.clone(), pat.clone(), &pos, &mut pos_map, &mut named_map); + let rebuilt_ex = final_rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); + // let rebuilt_ex = rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); + println!("rebuilt:{rebuilt_ex:?}\n\npos:\n{pos_map:?}\nnamed:\n{named_map:?}\n\n"); + + assert_eq!(m, *expected); + + if *expected { + assert_eq!(rebuilt_ex, ex.clone()); + } + } + } + + /// https://github.com/anandijain/cas3.rs/issues/1 + #[test] + fn issue_1() { + assert_eq!( + evalparse("(matchq (f a b 0 c) (f (blank_seq) 0 (blank_seq)))"), + sym("true") + ) + } + #[test] + fn table_tests() { + let mut ctx = Context2 { + vars: HashMap::new(), + }; + run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + ctx_evalparse(&mut ctx, "(set xs (List 1 2 3 4 5))"); + + let cases = vec![ + ("(Table f 3)", "(List f f f)"), + ("(Table i (List i 3))", "(List 1 2 3)"), + ("(Table i (List i 2 4))", "(List 2 3 4)"), + ("(Table i (List i 1 6 2))", "(List 1 3 5)"), + ("(Table i (List i (List 1.5 3.5)))", "(List 1.5 3.5)"), + ( + "(Table (List i j) (List i 2) (List j 2))", + "(List (List (List 1 1) (List 1 2)) (List (List 2 1) (List 2 2)))", + ), + ( + "(Table (Part xs (List i (Plus i 1) (Plus i 2))) (List i (Plus (Length xs) -2)))", + "(List (List 1 2 3) (List 2 3 4) (List 3 4 5))", + ), + ]; + for (lhs, rhs) in cases { + let res = ctx_evalparse(&mut ctx, lhs); + assert_eq!(res, expr_parser::Expr(rhs).unwrap()); + } + } + + #[test] + fn issue_2() { + let mut ctx = Context2 { + vars: HashMap::new(), + }; + run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + assert_eq!( + ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), + sym("true") + ) + } + + #[test] + fn alternatives_test() { + let mut ctx = Context2 { + vars: HashMap::new(), + }; + run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + let cases = vec![ + ("(matchq a (Alternatives a b))", sym("true")), + ("(matchq (f a) (f (Alternatives a b)))", sym("true")), + ( + "(matchq (f a b c) (Alternatives a (f (blank_seq))))", + sym("true"), + ), + ( + "(matchq (f a b c) (Alternatives a (f (pattern xs (blank_seq)))))", + sym("true"), + ), + ( + "(matchq (f a b c) (Alternatives a (f (blank_seq))))", + sym("true"), + ), + ( + "(matchq (f) (Alternatives a (f (blank_seq))))", + sym("false"), + ), + // ("(matchq a (Alternatives a b))", sym("true")), + ]; + + for (c, e) in cases { + assert_eq!(ctx_evalparse(&mut ctx, c), e) + } + } +} + +/* +exprs/programs to make work +1. + +(set x 1) +x +(set y 2) +(+ x y) => (+ 1 2). I don't think i want/need to implement arithmetic yet +2. +k[x_][y_] := x +(SetDelayed (k (pattern x (blank)) (pattern y (blank))) x) + +f[x_] := {x, x^2, x^3} +f[y] # gives {x, x^2, x^3} +(SetDelayed (f (pattern x (blank)) (list x (pow x 2) (pow x 3))) + +3. +(matchq x x) # true +(matchq x y) # false +(matchq x (pattern (blank))) # true +(matchq (list a) (pattern (blank))) # true + +4. (most important right now) +SetDelayed[fib[Pattern[n, Blank[]]], Plus[fib[Plus[n, -1]], fib[Plus[n, -2]]]]] + +(set (fib 1) (fib 0)) +(set (fib 0) 1) +(set_delayed (fib (pattern n (blank))) (plus (fib (minus n 1)) (fib (minus n 2)))) +(set_delayed (fib (pattern n (blank Int))) (plus (fib (minus n 1)) (fib (minus n 2)))) +(fib 5) + +okay so we make a new hashmap called DownValues that is a HashMap of symbol to list of exprs +this list of expr is all the downvalues. +so +f[x_][y_] := x +f[x_] := 1 + +f[x][y] # 1 + +k[x_][y_] := x +k[x][y] # x + +so it does the recursive thing, doesn't find any pattern matching (k x), which it looks to find first, shown by the f example +then goes out to see if there is a more nested pattern that matches, which is the k example + + +one thing that mathematica does is it actually stores (fib 2, 3,... ) in the evaluation of fib(5) + + +notes: +currently this crashes the interpreter because it goes into an infinite loop (no fixed point) +(set (f) (f f) +(set (f f) (f)) + +f[x_] := x +f[1] + +(setd (f (pattern x (blank))) (f x)) +(f 1) so basically wh + +(f (list 1)) + + +------ +TODO actually make testing + +(set (a b) c) +(a b) == c +(set b 1) +(a b) == (a 1) + +------ +need to make +(set x (plus x 1)) +crash the program +and +(setd x (plus x 1)) not +but (setd x (plus x 1)), (x) should crash the program + + + +f[x_]:=g[y_]:=y +f[1] === Null # True +but note that if you try to call g before f, then g is undefined +so +ff[x_]:=gg[y_]:=y +gg[1] # gives gg[1] +but then +ff[1] +gg[1] # now gives 1 + +also note that +x=1 +x=2 +works because Set is HoldFirst + + +https://mathematica.stackexchange.com/questions/176732/can-a-symbol-have-more-than-one-ownvalue +i will keep TableEntry.own as a list expr, but since I am not going to do conditional evaluation, it will only have one element +if set manually by the user, through OwnValues[x] = ..., i panic if more than one + +one interesting thing is how to set Set attributes to HoldFirst and Setd before calling Set and Setd. +maybe have to manually put in those DownValues of Attributes manually in rust and not in startup +can also just hardcode it in evaluate to never evaluate the first argument of Set and the rest + + +apply just replaces list with arg[1] +apply[f, {a, b, c}] # f[a, b, c] + + +*/ diff --git a/projects/cas3-core/src/main.rs b/projects/cas3-core/src/main.rs index 35902e8..59fc3f3 100644 --- a/projects/cas3-core/src/main.rs +++ b/projects/cas3-core/src/main.rs @@ -1,1593 +1,12 @@ -extern crate cairo; -extern crate peg; -use std::{ - borrow::Cow::{self, Borrowed, Owned}, - ops::{Add, Mul}, -}; - -use ordered_float::{self, NotNan}; -// use rug::Integer; -// use num_bigint::BigInt; -use num_traits::cast::ToPrimitive; - -use cairo::{Context, SvgSurface}; -use rustyline::{ - config::Configurer, - error::ReadlineError, - highlight::{Highlighter, MatchingBracketHighlighter}, - validate::MatchingBracketValidator, - Completer, Editor, Helper, Hinter, Result, Validator, -}; - use std::collections::HashMap; -use std::ops::{Deref, DerefMut}; -use std::time::{Duration, Instant}; -use std::{fmt, path::Path}; - -peg::parser! { - grammar expr_parser() for str { - rule comment() - = "(*" (!"*)" [_])* "*)" - - rule whitespace() = ([' ' | '\t' | '\n' | '\r'] / comment())* // Allow whitespace or comments - - rule integer() -> Expr - = n:$("-"? ['0'..='9']+ ) {? n.parse().map(Expr::Int).or(Err("integer")) } - - rule real() -> Expr - = n:$("-"? ['0'..='9']* "." ['0'..='9']* ) {? n.parse().map(Expr::Real).or(Err("real")) } - - rule symbol() -> Expr - = s:$(['a'..='z' | 'A'..='Z' | '?' | '$'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' ]* ) { Expr::Sym(s.into()) } - - rule string() -> Expr - = "\"" s:$((!['"'][_])* ) "\"" { Expr::Str(s.into()) } - - rule atom() -> Expr - = real() / integer() / symbol() / string() - - rule list() -> Expr - = "(" l:Expr() ** whitespace() ")" { Expr::List(l) } - - pub rule Expr() -> Expr - = whitespace() e:(atom() / list()) whitespace() { e } - - pub rule expressions() -> Vec - = whitespace() e:Expr() ** whitespace() { e } - } -} - -fn parse(s: &str) -> Expr { - expr_parser::Expr(s).unwrap() -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub enum Expr { - Int(num_bigint::BigInt), - // Int(Integer), - Real(ordered_float::NotNan), - Sym(String), - Str(String), - List(Vec), -} - -impl fmt::Display for Expr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Expr::Int(i) => write!(f, "{}", i), - Expr::Real(r) => write!(f, "{}", r), - Expr::Sym(s) => write!(f, "{}", s), - Expr::Str(s) => write!(f, "\"{}\"", s), - Expr::List(lst) => { - let str_list: Vec = lst.iter().map(|x| x.to_string()).collect(); - write!(f, "({})", str_list.join(" ")) - } - } - } -} - -impl Deref for Expr { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - match self { - Expr::List(vec) => vec, - e => panic!("Can only deref Expr::List. ex:{}", e), - } - } -} - -impl DerefMut for Expr { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - Expr::List(vec) => vec, - _ => panic!("Can only deref Expr::List"), - } - } -} - -pub fn sym(s: &str) -> Expr { - Expr::Sym(s.to_string()) -} - -fn list(strs: Vec<&str>) -> Expr { - Expr::List(strs.iter().map(|s| sym(s)).collect::>()) -} - -fn liste(es: Vec) -> Expr { - Expr::List(es) -} - -fn head(expr: &Expr) -> Expr { - match expr { - Expr::Int(_) => Expr::Sym("Int".to_string()), - Expr::Real(_) => Expr::Sym("Real".to_string()), - Expr::Sym(_) => Expr::Sym("Sym".to_string()), - Expr::Str(_) => Expr::Sym("Str".to_string()), - Expr::List(lst) => { - if let Some(first) = lst.first() { - first.clone() - } else { - println!("[ERROR]: empty list isnt allowed"); - Expr::Sym("GET_FUCKED".to_string()) - } - } - } -} - -fn length(expr: &Expr) -> Expr { - match expr { - Expr::List(es) => Expr::Int((es.len() - 1).into()), - _ => Expr::Int(0.into()), - } -} - -// (a b c) -> (b c) -// fn rest(expr: &Expr) -> Expr {} - -pub fn is_atom(expr: &Expr) -> bool { - match expr { - Expr::List(_) => false, - _ => true, - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Context2 { - vars: HashMap, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct TableEntry { - own: Option, - down: Expr, - sub: Expr, -} - -impl TableEntry { - pub fn new() -> Self { - Self { - own: None, - down: Expr::List(vec![sym("List")]), - sub: Expr::List(vec![sym("List")]), - } - } -} - -pub fn get_ownvalue(ctx: &Context2, sym: Expr) -> Option { - // println!("ctx: {:?}. sym: {}", ctx, sym); - let te = ctx.vars.get(&sym); - if let Some(te) = te { - let rule = te.own.clone(); - return rule; - // for now, since I'm only allowing a single ownvalue maybe im not going to do the whole handling of HoldPattern[lhs] :> rhs - // where i actually take sym and do sym /. OwnValues[sym] - // apply_rule() - } else { - None - } -} - -/// i hate this function -fn unpack_mat(ex: Expr) -> Option>> { - let mut result: Vec> = vec![]; - - if let Expr::List(outer_list) = ex { - // println!("outerr elem: {:?}", outer_list[0]); - for outer_elem in &outer_list[1..] { - if let Expr::List(inner_list) = outer_elem { - let mut inner_vec: Vec<(f64, f64, f64)> = vec![]; - // println!("inner elem: {:?}", inner_list[0]); - for inner_elem in &inner_list[1..] { - if let Expr::List(tuple_list) = inner_elem { - // println!("tuple_list: {:?}", tuple_list); - if tuple_list.len() == 4 { - if let (Expr::Real(a), Expr::Real(b), Expr::Real(c)) = - (&tuple_list[1], &tuple_list[2], &tuple_list[3]) - { - inner_vec.push((a.into_inner(), b.into_inner(), c.into_inner())); - } else { - return None; // one of the elements was not a Real - } - } else { - return None; // tuple_list did not contain exactly 3 elements - } - } else { - return None; // inner_elem was not a List - } - } - result.push(inner_vec); - } else { - return None; // outer_elem was not a List - } - } - Some(result) - } else { - None // ex was not a List - } -} - -fn create_svg_from_colors(colors: Vec>, filename: &str, scale_factor: i32) { - let rows = colors.len(); - let cols = colors[0].len(); // Assuming all rows have the same length - - let width = cols as i32 * scale_factor; - let height = rows as i32 * scale_factor; - - // Create SvgSurface - let surface = SvgSurface::new(width as f64, height as f64, Some(filename)) - .expect("Couldn't create SVG surface"); - - // Create Context for drawing - let cr = Context::new(&surface).expect("Couldn't create Cairo context"); - - // Scale the coordinate system - cr.scale(scale_factor as f64, scale_factor as f64); - - // Loop through each cell to draw rectangles with specified colors - for (i, row) in colors.iter().enumerate() { - for (j, &(r, g, b)) in row.iter().enumerate() { - cr.rectangle(j as f64, i as f64, 1.0, 1.0); - cr.set_source_rgb(r, g, b); - cr.fill().expect("Failed to fill rectangle"); - } - } - - // Finish drawing - cr.show_page().expect("Failed to save SVG"); -} - -// fn export() - -// are we guaranteed that we have a list here? -// can evaluated_args be empty -// nh can be List too -pub fn internal_functions_apply( - stack: &mut Expr, - ctx: &mut Context2, - nh: Expr, - evaluated_args: Vec, -) -> Expr { - let reconstructed_ex = Expr::List( - std::iter::once(nh.clone()) - .chain(evaluated_args.clone().to_owned()) - .collect(), - ); - - if nh == sym("matchq") { - if evaluated_args.len() != 2 { - println!("matchq takes 2 arguments"); - return sym("$Failed"); - } - return Expr::Sym(format!( - "{}", - my_match( - evaluated_args[0].clone(), - evaluated_args[1].clone(), - &vec![], - &mut HashMap::new(), - &mut HashMap::new() - ) - )); - } else if nh == sym("sameq") { - // println!("in sameq: evaluated_args: {:?}", evaluated_args); - let first_arg = &evaluated_args[0]; - let all_same = evaluated_args.iter().all(|arg| arg == first_arg); - return Expr::Sym(format!("{}", all_same)); - } else if nh == sym("replace") { - return replace(&evaluated_args[0], &evaluated_args[1]); - } else if nh == sym("replace_all") { - return replace_all(&evaluated_args[0], &evaluated_args[1]); - } else if nh == sym("rr") || nh == sym("replace_repeated") { - if evaluated_args.len() != 2 { - println!("replace_repeated takes 2 arguments"); - return sym("$Failed"); - } - return replace_repeated(&evaluated_args[0], &evaluated_args[1]); - } else if nh == sym("head") { - return head(&evaluated_args[0]); - } else if nh == sym("parse") { - match evaluated_args[0] { - Expr::Str(ref s) => { - let pex = expr_parser::Expr(s); - match pex { - Ok(expr) => return expr, - Err(err) => { - println!("Failed to parse: {}", err); - return sym("$Failed"); - } - } - } - _ => { - println!("parse takes a string"); - return sym("$Failed"); - } - } - } else if nh == sym("set") { - // array part setting notes: - // (set l (Table false 9)) - // simple single assignment case - // (set (Part l 1) 3) - - // this is the more advanced case setting multiple at the same time - // (set (Part l (list 1 2 3)) (Table true 3)) - - // println!("evaluated_args: {:?}", evaluated_args); - let lhs = &evaluated_args[0]; - let rhs = &evaluated_args[1]; - - match lhs { - // ownvalue - Expr::Sym(ref s) => { - // pretty sure this needs to be fixed to check if te already exists - let mut te = TableEntry::new(); - te.own = Some(evaluated_args[1].clone()); - ctx.vars.insert(sym(s), te); - return evaluated_args[1].clone(); - } - // this is the down/subvalue case - Expr::List(ls) => { - let lhs_h = &ls[0]; - match lhs_h { - // lhs_h is the tag in this downvalue assignment - Expr::Sym(_) => { - // todo: implementing list inplace modification - // if lhs_h == &sym("Part") { - // let part_lhs = &ls[1]; - // let part_rhs = &ls[2]; - // assert_eq!(length(rhs), length(part_rhs)); - // } - //given - // (set (f (pattern x (blank))) x) - // we end up pushing - // (rule_delayed (holdpattern expr[1]) expr[2]) - // (rule_delayed (holdpattern evaluated_args[0]) evaluated_args[1]) - // onto the downvalues of h (which is expected to have head list) - let te: &mut TableEntry = ctx - .vars - .entry(lhs_h.clone()) - .or_insert_with(TableEntry::new); - let dv_str = format!("(rule_delayed (hold_pattern {lhs}) {rhs})"); - let dv = expr_parser::Expr(&dv_str).unwrap(); - - // NOTE! here we aren't inserting in the right order, where we look for more specific - // definitions and insert them first. so user has to do the right order themselves - // at the moment - te.down.push(dv); - return rhs.clone(); - } - // subvalue - Expr::List(_) => { - todo!("subvalues") - } - _ => { - let h = head(lhs_h); - println!("Tag {h} in {lhs} is Protected"); - return rhs.clone(); - } - } - } - _ => { - println!("set takes a symbol or list, got {}", lhs); - return sym("$Failed"); - } - } - } else if nh == sym("setd") { - // println!("evaluated_args: {:?}", evaluated_args); - let lhs = &evaluated_args[0]; - match lhs { - Expr::Sym(ref s) => { - // pretty sure this needs to be fixed to check if te already exists - let mut te = TableEntry::new(); - te.own = Some(evaluated_args[1].clone()); - ctx.vars.insert(sym(s), te); - return sym("Null"); - } - // this is the down/subvalue case - Expr::List(ls) => { - let lhs_h = &ls[0]; - match lhs_h { - // lhs_h is the tag in this downvalue assignment - Expr::Sym(_) => { - let rhs = &evaluated_args[1]; - // onto the downvalues of h (which is expected to have head list) - let te: &mut TableEntry = ctx - .vars - .entry(lhs_h.clone()) - .or_insert_with(TableEntry::new); - let dv_str = format!("(rule_delayed (hold_pattern {lhs}) {rhs})"); - let dv = expr_parser::Expr(&dv_str).unwrap(); - - // NOTE! here we aren't inserting in the right order, where we look for more specific - // definitions and insert them first. so user has to do the right order themselves - // at the moment - te.down.push(dv); - return sym("Null"); - } - // subvalue - Expr::List(_) => { - todo!("subvalues") - } - _ => panic!("hi"), - } - } - _ => { - println!("set takes a symbol or list, got {}", lhs); - return sym("$Failed"); - } - } - } else if nh == sym("own_values") { - ctx.vars - .get(&evaluated_args[0]) - .unwrap() // there is a bug here - .own - .clone() - .unwrap() - // todo!() - } else if nh == sym("down_values") { - ctx.vars.get(&evaluated_args[0]).unwrap().down.clone() - } else if nh == sym("sub_values") { - todo!() - } else if nh == sym("clear") { - match &evaluated_args[0] { - Expr::Sym(_) => { - if let Some(te) = ctx.vars.get_mut(&evaluated_args[0]) { - te.own = None; - te.down = Expr::List(vec![sym("List")]); - te.sub = Expr::List(vec![sym("List")]); - } - return sym("Null"); - } - _ => { - println!("set takes a symbol"); - return sym("$Failed"); - } - } - } else if nh == sym("Plus") { - match (&evaluated_args[0], &evaluated_args[1]) { - (Expr::Int(a), Expr::Int(b)) => Expr::Int(a.add(b).into()), - // see issue about 3.0 printing as `3` - // (Expr::Real(a), Expr::Real(b)) => Expr::Real(a + b), - _ => { - let reconstructed_ex = Expr::List( - std::iter::once(nh.clone()) - .chain(evaluated_args.clone().to_owned()) - .collect(), - ); - return reconstructed_ex; - } - } - } else if nh == sym("Times") { - match (&evaluated_args[0], &evaluated_args[1]) { - (Expr::Int(a), Expr::Int(b)) => Expr::Int(a.mul(b).into()), - _ => { - return reconstructed_ex; - } - } - } else if nh == sym("Part") { - match &evaluated_args[0] { - Expr::List(ls) => match &evaluated_args[1] { - Expr::Int(i) => { - let i = i.to_isize().unwrap(); - if i < 0 || i >= ls.len() as isize { - println!("Part: index {} out of range", i); - return reconstructed_ex; - } - return ls[i as usize].clone(); - } - Expr::List(indices) => { - let mut results = vec![sym("List")]; - for index in indices[1..].iter() { - match index { - Expr::Int(i) => { - let i = i.to_isize().unwrap(); - if i < 0 || i >= ls.len() as isize { - println!("Part: index {} out of range", i); - return reconstructed_ex; - } - results.push(ls[i as usize].clone()); - } - _ => { - // println!("Part: each index in the list must be an integer"); - return reconstructed_ex; - } - } - } - return Expr::List(results); - } - _ => { - // println!("Part: index must be an integer or a list of integers"); - return reconstructed_ex; - } - }, - _ => return reconstructed_ex, - } - } else if nh == sym("Length") { - return length(&evaluated_args[0]); - } else if nh == sym("Get") { - if let Expr::Str(p) = &evaluated_args[0] { - let res = run_file(ctx, Path::new(&p)); - if let Ok(res) = res { - return res; - } else { - return sym("$Failed"); - } - } else { - println!("Get takes an Expr::String"); - return sym("$Failed"); - } - } else if nh == sym("Map") { - // todo level spec - // honestly i was hoping i could do this in cas3, not builtin but just to get things going - - let mut res = liste(vec![head(&evaluated_args[1])]); - let f = &evaluated_args[0]; - let mapargs = &evaluated_args[1]; - - for (_i, arg) in mapargs[1..].iter().enumerate() { - let fi = Expr::List(vec![f.clone(), arg.clone()]); - res.push(fi); - } - return res; - } else if nh == sym("NestList") { - let f = &evaluated_args[0]; - let x = &evaluated_args[1]; - let n = &evaluated_args[2]; - let mut res = list(vec!["List"]); - res.push(x.clone()); - if let Expr::Int(count) = n { - for _i in 0..count.to_i64().unwrap() { - let fi = evaluate( - stack, - ctx, - &Expr::List(vec![f.clone(), res.last().unwrap().clone()]), - ); - res.push(fi); - } - return res; - } else { - return reconstructed_ex; - } - } else if nh == sym("Table") { - let table_body = &evaluated_args[0]; - - // todo: test if this works implemented in cas3 code - if evaluated_args.len() == 1 { - return table_body.clone(); - } - let spec = evaluate(stack, ctx, &evaluated_args[1].clone()); - - if evaluated_args.len() == 2 { - // if int, we copy n times - if let Expr::Int(n) = &spec { - return Expr::List( - std::iter::once(sym("List")) - .chain((0..n.to_i64().unwrap()).map(|_| evaluated_args[0].clone())) - .collect(), - ); - } else if let Expr::List(ls) = &spec { - // this is the place where we want to make helpers for - // the "standard Wolfram Language iteration specification" - - let mut res = Expr::List(vec![sym("List")]); - let var = &ls[1]; - - // this specific case is {i, imax} - if ls.len() == 3 { - if ls[0] != sym("List") { - dbg!("invalid range specification. need a list"); - // return reconstructed_ex; - } - if let Expr::Int(imax) = &ls[2] { - for i in 1..=imax.to_i64().unwrap() { - let mut e_i = Expr::List(vec![sym("replace_all")]); - e_i.push(table_body.clone()); - let local_rule = - Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) - e_i.push(local_rule); - res.push(e_i); - } - return res; - } else if let Expr::List(vals) = &ls[2] { - // this is the sequence case where you just - // Table[expr,{i,{i1,i2,…}}] - - if head(&ls[2]) != sym("List") { - dbg!( - "invalid range specification. need a list of values, gave {}", - &ls[2] - ); - // return reconstructed_ex; - } else { - for val in &vals[1..] { - let mut e_i = Expr::List(vec![sym("replace_all")]); - e_i.push(table_body.clone()); - let local_rule = - Expr::List(vec![sym("rule"), var.clone(), val.clone()]); // (rule var iter) - e_i.push(local_rule); - res.push(e_i); - } - return res; - } - } else { - dbg!("need an int or list for imax, reals not supported in iteration specification yet"); - return sym("$Failed"); - } - } else if ls.len() == 4 { - // this is {i, imin, imax} - if let (Expr::Int(imin), Expr::Int(imax)) = (&ls[2], &ls[3]) { - for i in imin.to_i64().unwrap()..=imax.to_i64().unwrap() { - let mut e_i = Expr::List(vec![sym("replace_all")]); - e_i.push(table_body.clone()); - let local_rule = - Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) - e_i.push(local_rule); - res.push(e_i); - } - return res; - } else { - // this is the sequence case where you just - // Table[expr,{i,{i1,i2,…}}] - dbg!("need an int or list for imax, reals not supported in iteration specification yet"); - return sym("$Failed"); - } - } else if ls.len() == 5 { - // this is {i, imin, imax, di} - // this is {i, imin, imax} - if let [Expr::Int(imin), Expr::Int(imax), Expr::Int(di)] = &ls[2..] { - let rng = imin.to_i64().unwrap()..=imax.to_i64().unwrap(); - let iter = rng.step_by(di.to_i64().unwrap() as usize); - for i in iter { - let mut e_i = Expr::List(vec![sym("replace_all")]); - e_i.push(table_body.clone()); - let local_rule = - Expr::List(vec![sym("rule"), var.clone(), Expr::Int(i.into())]); // (rule var iter) - e_i.push(local_rule); - res.push(e_i); - } - return res; - } else { - // this is the sequence case where you just - // Table[expr,{i,{i1,i2,…}}] - dbg!("need an int or list for imax, reals not supported in iteration specification yet"); - return sym("$Failed"); - } - } - } - } - - let range_lists = &evaluated_args[1..]; //.clone().reverse(); - // Table[ f[i,j], {i, imin, imax}, {j, jmin, jmax}] - // Table[Table[f[i,j], {j, jmin, jmax}], {i, imin, imax}] - // let mut ex = Expr::List(vec![sym("Table")]); - // ex.push(table_body.clone()); - - let mut nested_table = table_body.clone(); - for range in range_lists.iter().rev() { - let mut new_table = Expr::List(vec![sym("Table"), nested_table.clone()]); - new_table = match &mut new_table { - Expr::List(ref mut v) => { - v.push(range.clone()); - new_table.clone() - } - _ => panic!("Unexpected expression type"), - }; - nested_table = new_table; - } - return nested_table; - } else if nh == sym("Join") { - if !matches!(&evaluated_args[0], Expr::List(ls)) { - println!("Join joins lists dummy!"); - return reconstructed_ex; - } - - let ha = head(&evaluated_args[0]); - - let mut res = vec![ha.clone()]; - for e in evaluated_args { - if ha != head(&e) { - println!("Join: heads of arguments are not all the same"); - return reconstructed_ex; - } - if let Expr::List(ls) = e { - res.append(&mut ls[1..].to_vec()); - } else { - //fix - return sym("Failed"); - } - } - return Expr::List(res); - } else if nh == sym("Timing") { - let t1 = Instant::now(); - let res = evaluate(stack, ctx, &evaluated_args[0]); - let dt = t1.elapsed(); // Capture the elapsed time - - // Convert duration to seconds - let elapsed_seconds = dt.as_secs() as f64 + dt.subsec_nanos() as f64 * 1e-9; - // NotNan - Expr::List(vec![ - sym("List"), - Expr::Real(NotNan::new(elapsed_seconds).unwrap()), - res, - ]) - } else if nh == sym("Export") { - let dst = &evaluated_args[0]; - let ex = &evaluated_args[1]; - // println!("ex: {:?}", ex); - let m = unpack_mat(ex.clone()).unwrap(); - let filename = match dst { - Expr::Str(s) => s, - _ => { - println!("Export: first argument must be a string"); - return sym("$Failed"); - } - }; - create_svg_from_colors(m, filename, 50); - return sym("Null"); - } else { - return Expr::List( - std::iter::once(nh.clone()) - .chain(evaluated_args.clone().to_owned()) - .collect(), - ); - } -} - -pub fn evaluate(stack: &mut Expr, ctx: &mut Context2, expr: &Expr) -> Expr { - let mut ex = expr.clone(); - let mut last_ex = None; - - loop { - if Some(&ex) == last_ex.as_ref() { - // If the expression hasn't changed, break the loop. - break; - } - // println!("evaluating: {}", ex); - - last_ex = Some(ex.clone()); - - match &ex { - Expr::Int(_) | Expr::Real(_) | Expr::Str(_) => { - break; - } - Expr::Sym(ref s) => { - if let Some(rule) = get_ownvalue(ctx, sym(s)) { - ex = rule; - } else { - break; - } - } - Expr::List(ref ls) => { - let h; - if let Some(sh) = ls.first() { - h = sh; - } else { - println!("Expr::List needs a head"); - return sym("$Failed"); - } - // step 5 - let mut nh = evaluate(stack, ctx, h); - - // step 6 - // the use of a separate stack here is questionable - // also to note that when we use "contains" on it, we also do a comparison against the head ("List"), which is wrong - // but for practical purposes shouldn't cause a problem - - // the most important next step here is making sure that (attrs set) works correctly - // note that something here causes SO - - // a potential problem here is that nh is not necesarily an atom - // nh can be Expr::List - - // 3a (we might be able to just replace_all((attrs h) (down_values attrs))) - // nvm 3a is less easy to see that a match wastn found - - // println!("hi"); - - // 1. assume h::Sym - // 2. get dvs of attr - // 3. find a matching rule in dvs to (attrs h) - // if no matching rule found, return "(List)" - - let mut nh_attrs = Expr::List(vec![sym("List")]); - // #16 - this is what we need to speed up. ideally bypass the pattern matcher somehow - // we know/can assume we are looking up (attrs SYM) - if let Expr::Sym(_) = nh.clone() { - let te = ctx.vars.entry(sym("attrs")).or_insert_with(TableEntry::new); - // (down_values attrs) - let dvs = &te.down; - let attr_expr = - expr_parser::Expr(&format!("(attrs {})", nh).to_string()).unwrap(); - // println!("attr_expr: {}", attr_expr); - if let Expr::List(_ls) = dvs { - // dv expected to be (rule_delayed (hold_pattern lhs) rhs) - for dv in &_ls[1..] { - let mut pos_map = HashMap::new(); - let mut named_map = HashMap::new(); - let pos = vec![]; - if my_match( - attr_expr.clone(), - dv[1].clone(), - &pos, - &mut pos_map, - &mut named_map, - ) { - // println!("found attributes match for {} -> {}", nh, dv); - nh_attrs = replace(&attr_expr, dv); - break; // Exit the loop once a match is found - } - } - } else { - panic!("down_values must be a list"); - } - } - - // println!("nh_attrs: {:?}", nh_attrs); - // assert!(head(&nh_attrs) == sym("List")); - if nh_attrs.contains(&sym("HoldAllComplete")) { - // skip to 14 - todo!(); - } - - // step 7 - let mut evaluated_args = vec![]; - - // hold_mask entry with a zero means "don't hold" - let mut hold_mask = vec![false; ls.len() - 1]; - - // idk if it should be else ifs - if nh_attrs.contains(&sym("HoldAll")) { - hold_mask.fill(true); - } - if nh_attrs.contains(&sym("HoldFirst")) { - hold_mask[0] = true; - } - if nh_attrs.contains(&sym("HoldRest")) { - hold_mask[1..].fill(true); - } - // println!("hold_mask: {:?}", hold_mask); - - for (i, p) in ls[1..].iter().enumerate() { - if hold_mask[i] { - evaluated_args.push(p.clone()); - } else { - let ev = evaluate(stack, ctx, p); - - evaluated_args.push(ev); - } - } - - if !nh_attrs.contains(&sym("SequenceHold")) { - let mut arg_idx = 0; - while arg_idx < evaluated_args.len() { - if head(&evaluated_args[arg_idx]) == sym("Sequence") { - let seq_args: Vec<_> = evaluated_args[arg_idx][1..].to_vec(); - evaluated_args.splice(arg_idx..arg_idx + 1, seq_args); - } else { - arg_idx += 1; - } - } - } - let reconstructed_ex = Expr::List( - std::iter::once(nh.clone()) - .chain(evaluated_args.clone().to_owned()) - .collect(), - ); - // println!("reconstructed_ex: {}", reconstructed_ex); - - // step 14: apply user defined downvalues and subvalues - let exprime = match nh.clone() { - // we dont need to panic here "abc"[foo] doesn't - Expr::Int(_) | Expr::Real(_) | Expr::Str(_) => { - // note: WL doesn't give note in this case - println!("head must be a symbol, got {nh}"); - return reconstructed_ex; - } - // this is the down_value case, bcause the head - Expr::Sym(_) => { - let te = ctx.vars.entry(nh.clone()).or_insert_with(TableEntry::new); - let dvs = &te.down; - // println!("looking for user defined down_values for {} -> {}", nh, dvs); - - // should this be replace_all? or replace_repeated? - - let exprime = replace_all(&reconstructed_ex, dvs); - // println!("before: {}", reconstructed_ex); - // println!("after: {}", exprime); - exprime - } - // subvalue - Expr::List(_) => reconstructed_ex.clone(), - }; - - // im not sure if this is correct, but it seems necesary, - // if we found a matching downvalue rule, then we need to re-evaluate the expression after replacement - if ex != exprime { - ex = exprime; - continue; - } - - // note now that ex is not necesarily a List anymore - // so if we still have a list, then we do step 15, and apply internal down/subvalues - - match ex { - Expr::List(_) => {} - _ => continue, - } - nh = head(&ex); - evaluated_args = ex[1..].to_vec(); - // this corresponds to step 15 in Wagner's main eval loop section - // where we apply internal/builtin down and subvalues - ex = internal_functions_apply(stack, ctx, nh, evaluated_args); - } - } - } - // println!("exiting evaluate: {}", ex); - ex -} - -fn named_rebuild_all(expr: Expr, map: &HashMap) -> Expr { - // First, check if the entire expression exists in the map and replace it if it does - if let Some(replacement) = map.get(&expr) { - return replacement.clone(); - } - - // If the expression is not in the map, proceed with the recursion - match expr { - Expr::List(list) => { - // Recursively rebuild all sub-expressions in the list - let new_list: Vec = list - .into_iter() - .map(|e| named_rebuild_all(e, map)) - .collect(); - Expr::List(new_list) - } - _ => expr, - } -} - -// this adjusts lookups to the position map based on the sequences found in the current list -fn final_pos_map_rebuild(pos: Vec, pat: Expr, pos_map: &HashMap, Expr>) -> Expr { - // println!("pos: {:?}, pat: {}", pos, pat); - if let Some(replacement) = pos_map.get(&pos) { - return replacement.clone(); - } - - match pat { - Expr::List(es) => { - let mut new_es = vec![]; - // note in the case of blank_null_seq, this can be negative - let mut offset: isize = 0; - for (i, e) in es.iter().enumerate() { - let mut new_pos = pos.clone(); - let pos_in_list = i as isize + offset; - // println!("{i}, pos_in_list: {} offset:{offset}", pos_in_list); - new_pos.push(pos_in_list as usize); - let new_e = final_pos_map_rebuild(new_pos, e.clone(), pos_map); - if head(&new_e) == sym("Sequence") { - offset += new_e.len() as isize - 2; // its -2 becasue 1 for the head and 1 for the original (blank_seq) object - } - // so pos[0..i-1] is the position of the current list - // we want to then look for all the position keys that have thsi as a prefix and adjust them - // but i think we only want to adjust on a final rebuild but not in the middle. - // when we are at the end of a list we are confirming the map works but haven't rebuilt anything, so our pat is still the original - // println!("{i}, new_e: {} offest: {offset}", new_e); - new_es.push(new_e); - } - Expr::List(new_es) - } - _ => pat, - } -} - -/// to fix pos_map. as you iterate es, and you keep track of the offset for the current list. -/// then you want to adjust lookups into the posmap based on the position - offset. -/// the reason we still need this is for intermediate rebuilds where we have already spliced former sequences -fn pos_map_rebuild(pos: Vec, pat: Expr, pos_map: &HashMap, Expr>) -> Expr { - if let Some(replacement) = pos_map.get(&pos) { - return replacement.clone(); - } - - match pat { - Expr::List(es) => { - let mut new_es = vec![]; - // note in the case of blank_null_seq, this can be negative - for (i, e) in es.iter().enumerate() { - let mut new_pos = pos.clone(); - new_pos.push(i); - let new_e = pos_map_rebuild(new_pos, e.clone(), pos_map); - new_es.push(new_e); - } - Expr::List(new_es) - } - _ => pat, - } -} - -fn splice_sequences(expr: Expr) -> Expr { - match expr { - Expr::List(mut list) => { - let mut i = 0; - while i < list.len() { - list[i] = splice_sequences(list[i].clone()); - i += 1; - } - - let mut new_list = Vec::new(); - let mut i = 0; - while i < list.len() { - let item = list[i].clone(); - if let Expr::List(ref sublist) = item { - if let Some(Expr::Sym(head)) = sublist.first() { - if head == "Sequence" { - new_list.extend_from_slice(&sublist[1..]); - i += 1; - continue; - } - } - } - new_list.push(item); - i += 1; - } - Expr::List(new_list) - } - _ => expr, - } -} - -fn rebuild_and_splice( - pat: Expr, - pos: &Vec, - pos_map: &HashMap, Expr>, - named_map: &HashMap, -) -> Expr { - splice_sequences(named_rebuild_all( - pos_map_rebuild(pos.clone(), pat, pos_map), - named_map, - )) -} - -fn final_rebuild_and_splice( - pat: Expr, - pos: &Vec, - pos_map: &HashMap, Expr>, - named_map: &HashMap, -) -> Expr { - splice_sequences(named_rebuild_all( - final_pos_map_rebuild(pos.clone(), pat, pos_map), - named_map, - )) -} - -// we assume that p has a blank object for a head -fn is_blank_match(e: Expr, p: Expr) -> bool { - if let Expr::List(ps) = p { - if ps.len() == 2 { - let p_head = &ps[1]; - if p_head == &head(&e) { - true - } else { - false - } - } else { - true - } - } else { - panic!("is_blank_match needs a list for p") - } -} - -fn my_match( - ex: Expr, - mut pat: Expr, - pos: &Vec, - pos_map: &mut HashMap, Expr>, - named_map: &mut HashMap, -) -> bool { - let pattern_expr = pat.clone(); - if head(&pattern_expr) == sym("hold_pattern") { - pat = pattern_expr[1].clone(); - } - // if head(&pat) != sym("attrs") && pat != sym("attrs") && ex != sym("matchq") { - // println!("M: {pos:?} | {ex} | {pat} | {pos_map:?} | {named_map:?}"); - // } - - let pat_syms = vec![sym("blank"), sym("blank_seq"), sym("blank_null_seq")]; - if head(&pat) == sym("Alternatives") { - for p in &pat[1..] { - if my_match(ex.clone(), p.clone(), pos, pos_map, named_map) { - pos_map.insert(pos.clone(), p.clone()); - return true; - } - } - return false; - } - - match (ex.clone(), pat.clone()) { - (Expr::List(es), Expr::List(ps)) => { - // this first block determines if the pattern matches the entire list - if ps[0] == sym("pattern") { - if let Some(from_map) = named_map.get(&pat) { - return &ex == from_map; - } else { - if is_blank_match(ex.clone(), ps[2].clone()) { - named_map.insert(pat.clone(), ex.clone()); - return true; - } - } - } else if pat_syms.contains(&ps[0]) { - if is_blank_match(ex.clone(), pat.clone()) { - pos_map.insert(pos.clone(), ex); - return true; - } - } - - let mut new_pos = pos.clone(); - new_pos.push(0); // we are at the head - if !my_match(es[0].clone(), ps[0].clone(), &new_pos, pos_map, named_map) { - return false; - } - - 'outer: for (i, pi) in ps.iter().enumerate().skip(1) { - let mut new_pos = pos.clone(); - new_pos.push(i); // we are at the head - if head(pi) == sym("pattern") { - // println!("in pattern pi "); - if let Some(_from_map) = named_map.get(&pi) { - // here is an example that contradicts the below i think - // (setd (Times (pattern x (blank Sym)) (pattern x (blank Sym))) (Pow x 2)) - println!("we should have rebuilt to remove this i think"); - } - let b = &pi[2]; - let bt = &b[0]; - // let p_name = &pi[1]; - if bt == &sym("blank_seq") { - for j in 1..=es[1..].len() { - let mut elts = vec![sym("Sequence")]; - // im pretty sure this is not needed - if i + j > es.len() { - // println!("breaking news!"); - break 'outer; - } - for seq_e in &es[i..i + j] { - if b.len() == 2 { - let b_head = &b[1]; - if b_head != &head(seq_e) { - break; - } - } - elts.push(seq_e.clone()); - } - let seq = liste(elts); - named_map.insert(pi.clone(), seq.clone()); - - let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - // println!("new_pat in bs: at iter {j} {new_pat} {seq}"); - if my_match(ex.clone(), new_pat, pos, pos_map, named_map) { - break 'outer; - } - } - } else if bt == &sym("blank_null_seq") { - for j in 0..=es[1..].len() { - let mut elts = vec![sym("Sequence")]; - // im pretty sure this is not needed - if i + j > es.len() { - // println!("breaking news!"); - break 'outer; - } - for seq_e in &es[i..i + j] { - if b.len() == 2 { - let b_head = &b[1]; - if b_head != &head(seq_e) { - break; - } - } - elts.push(seq_e.clone()); - } - let seq = liste(elts); - named_map.insert(pi.clone(), seq.clone()); - - let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - // println!("new_pat in bs: at iter {j} {new_pat} {seq}"); - if my_match(ex.clone(), new_pat, pos, pos_map, named_map) { - break 'outer; - } - } - } else { - if i >= es.len() { - break 'outer; - } - // named blank case - if !my_match(es[i].clone(), ps[i].clone(), &new_pos, pos_map, named_map) { - break 'outer; - } - } - } else if head(pi) == sym("blank_seq") { - for j in 1..=es[1..].len() { - let mut elts = vec![sym("Sequence")]; - // im pretty sure this is not needed - if i + j > es.len() { - // println!("breaking news!"); - break 'outer; - } - for seq_e in &es[i..i + j] { - if pi.len() == 2 { - let b_head = &pi[1]; - if b_head != &head(seq_e) { - break; - } - } - elts.push(seq_e.clone()); - } - let seq = liste(elts); - pos_map.insert(new_pos.clone(), seq.clone()); - - let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - // println!("new_pat in bs: at iter {j} {new_pat}"); - let mut copy = pos_map.clone(); - // this is to avoid double application of a pos rule - copy.remove(&new_pos); - // if my_match(ex.clone(), pat.clone(), pos, &mut copy) { - if my_match(ex.clone(), new_pat, pos, &mut copy, named_map) { - pos_map.clear(); - pos_map.extend(copy); - - pos_map.insert(new_pos.clone(), seq.clone()); - - break 'outer; - } else { - // break 'outer; - // i think we need to revert pos_map to whatever it was before this my_match call - } - } - } else if head(pi) == sym("blank_null_seq") { - for j in 0..=es[1..].len() { - let mut elts = vec![sym("Sequence")]; - // im pretty sure this is not needed - if i + j > es.len() { - println!("breaking news!"); - break 'outer; - } - for seq_e in &es[i..i + j] { - if pi.len() == 2 { - let b_head = &pi[1]; - if b_head != &head(seq_e) { - break; - } - } - elts.push(seq_e.clone()); - } - let seq = liste(elts); - pos_map.insert(new_pos.clone(), seq.clone()); - - let new_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - // println!("new_pat in bs: at iter {j} {new_pat}"); - let mut copy = pos_map.clone(); - // this is to avoid double application of a pos rule - copy.remove(&new_pos); - // if my_match(ex.clone(), pat.clone(), pos, &mut copy) { - if my_match(ex.clone(), new_pat, pos, &mut copy, named_map) { - pos_map.clear(); - pos_map.extend(copy); - - pos_map.insert(new_pos.clone(), seq.clone()); - - break 'outer; - } else { - // break 'outer; - // i think we need to revert pos_map to whatever it was before this my_match call - } - } - } else { - if i >= es.len() { - break 'outer; - } - if !my_match(es[i].clone(), ps[i].clone(), &new_pos, pos_map, named_map) { - break 'outer; - } - } - } - let final_pat = final_rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - // let final_pat = rebuild_and_splice(pat.clone(), &pos, pos_map, named_map); - - // todo remove these conditions when we fast path attribute lookup - // if head(&pat) != sym("attrs") && pat != sym("attrs") { - // println!("final comparison: POS: {pos:?} | PAT: {pat} | NEW_PAT: {final_pat} | EX: {ex} || pos {pos_map:?} || named {named_map:?}"); - // } - if final_pat == ex { - return true; - } - false - } - (_, Expr::List(ps)) => { - if ps[0] == sym("pattern") { - if let Some(from_map) = named_map.get(&pat) { - return &ex == from_map; - } else { - if is_blank_match(ex.clone(), ps[2].clone()) { - named_map.insert(pat.clone(), ex.clone()); - true - } else { - false - } - } - } else if pat_syms.contains(&ps[0]) { - if is_blank_match(ex.clone(), pat.clone()) { - pos_map.insert(pos.clone(), ex); - true - } else { - false - } - } else { - false - } - } - _ => ex == pat, - } -} - -pub fn bindings_to_rules(bindings: &HashMap) -> Expr { - let mut rules = Expr::List(vec![sym("List")]); - for (name, binding) in bindings.clone() { - rules.push(Expr::List(vec![sym("rule"), sym(&name), binding.clone()])); - } - rules -} - -pub fn pat_bindings_to_rules(bindings: &HashMap) -> Expr { - let mut rules = Expr::List(vec![sym("List")]); - for (pat, binding) in bindings.clone() { - if let Expr::List(ps) = pat { - let p_name = &ps[1]; // (pattern x (blank)) - rules.push(Expr::List(vec![ - sym("rule"), - p_name.clone(), - binding.clone(), - ])); - } - } - rules -} - -pub fn norm_rules(rules: &Expr) -> Vec { - if head(rules) == sym("rule") || head(rules) == sym("rule_delayed") { - return vec![rules.clone()]; - } else { - assert_eq!(head(rules), sym("List")); - return rules.clone()[1..].to_vec(); - }; -} - -pub fn replace(expr: &Expr, rules: &Expr) -> Expr { - let rules_list = norm_rules(rules); - - for rule in rules_list { - let pos = vec![]; - let mut pos_map = HashMap::new(); - let mut named_map = HashMap::new(); - assert!(head(&rule) == sym("rule") || head(&rule) == sym("rule_delayed")); - if my_match( - expr.clone(), - rule[1].clone(), - &pos, - &mut pos_map, - &mut named_map, - ) { - let mut new_expr = rule[2].clone(); - new_expr = replace_all(&new_expr, &pat_bindings_to_rules(&named_map)); - - return new_expr; - } - } - expr.clone() -} - -pub fn replace_all(expr: &Expr, rules: &Expr) -> Expr { - let rules_list = norm_rules(rules); - for rule in rules_list { - let pos = vec![]; - let mut pos_map = HashMap::new(); - let mut named_map = HashMap::new(); - assert!(head(&rule) == sym("rule") || head(&rule) == sym("rule_delayed")); - if my_match( - expr.clone(), - rule[1].clone(), - &pos, - &mut pos_map, - &mut named_map, - ) { - return replace(expr, &rule); - } - } - - match expr { - Expr::List(list) => { - let new_list: Vec = list - .iter() - .map(|sub_expr| replace_all(sub_expr, rules)) - .collect(); - Expr::List(new_list) - } - _ => replace(expr, rules), - } -} - -pub fn replace_repeated(expr: &Expr, rules: &Expr) -> Expr { - let mut current_expr = expr.clone(); - let mut i = 0; - loop { - let new_expr = replace_all(¤t_expr, rules); - if new_expr == current_expr { - break; - } - current_expr = new_expr; - i += 1; - if i > 1 << 16 { - println!("replace_repeated, iteration limit 1<<16 reached"); - break; - } - } - current_expr -} - -pub fn startup_attrs(ctx: &mut Context2) { - let attrs_te = ctx.vars.entry(sym("attrs")).or_insert_with(TableEntry::new); - let mut exs = vec![ - format!("(rule_delayed (hold_pattern (attrs hold_pattern)) (list HoldAll))"), - format!("(rule_delayed (hold_pattern (attrs attrs)) (list HoldAll))"), - format!("(rule_delayed (hold_pattern (attrs rule_delayed)) (list HoldRest SequenceHold))"), - format!("(rule_delayed (hold_pattern (attrs set)) (list HoldFirst SequenceHold))"), - format!("(rule_delayed (hold_pattern (attrs down_values)) (list HoldAll))"), - ] - .iter_mut() - .map(|s| expr_parser::Expr(&s).unwrap()) - .collect(); - attrs_te.down.append(&mut exs); -} - -#[derive(Helper, Completer, Hinter, Validator)] -pub struct ReplHelper { - highlighter: MatchingBracketHighlighter, - #[rustyline(Validator)] - validator: MatchingBracketValidator, - colored_prompt: String, -} - -impl Highlighter for ReplHelper { - fn highlight_prompt<'b, 's: 'b, 'p: 'b>( - &'s self, - prompt: &'p str, - default: bool, - ) -> Cow<'b, str> { - if default { - Borrowed(&self.colored_prompt) - } else { - Borrowed(prompt) - } - } - - fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { - Owned("\x1b[1m".to_owned() + hint + "\x1b[m") - } - - fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { - self.highlighter.highlight(line, pos) - } - - fn highlight_char(&self, line: &str, pos: usize) -> bool { - self.highlighter.highlight_char(line, pos) - } -} - -pub fn run_file(ctx: &mut Context2, filepath: &Path) -> Result { - // let file = File::open(filepath)?; - // let reader = BufReader::new(file); - let file_contents = std::fs::read_to_string(filepath)?; - // i dont love this because it's ambigious whether or not something failed in reading the file or sth - // or if the last expr in the file was a setd or something that returns a Null - println!("Running file: {}", filepath.display()); - let mut res = sym("Null"); - let exprs = expr_parser::expressions(&file_contents).unwrap(); - // for line in reader.lines() { - for expr in exprs { - // match line { - // Ok(content) => { - // if content.starts_with("//") || content.starts_with(";") || content.is_empty() { - // continue; - // } - // if let Ok(ex) = &expr_parser::Expr(&content) { - let mut stack = Expr::List(vec![]); - res = evaluate(&mut stack, ctx, &expr); - // } else { - // eprintln!("Error parsing a line: {:?}", content); - // } - } - // Err(error) => { - // eprintln!("Error reading a line: {:?}", error); - // } - // } - // } - - Ok(res) -} - -pub fn run( - mut rl: rustyline::Editor, - mut ctx: Context2, -) -> Result<()> { - let mut i = 1; - - loop { - let prompt = format!("(In {}) := ", i); - rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{prompt}\x1b[0m"); - - let line = rl.readline(&prompt); // read - match line { - Ok(l) => { - rl.add_history_entry(l.as_str()).unwrap(); // history - // saving every line (even if slow, just until its more stable) - rl.save_history("history.txt").unwrap(); - - let exs = expr_parser::expressions(&l); - - match exs { - Ok(exprs) => { - for expr in exprs { - let mut stack = Expr::List(vec![]); - let res = evaluate(&mut stack, &mut ctx, &expr); - let in_i = - expr_parser::Expr(format!("(setd (In {i}) {})", expr).as_str()) - .unwrap(); - evaluate(&mut stack, &mut ctx, &in_i); - let out_i = - expr_parser::Expr(format!("(set (Out {i}) {})", res).as_str()) - .unwrap(); - evaluate(&mut stack, &mut ctx, &out_i); - - println!("\x1B[1m(Out {i}) = {}\x1B[0m", res); - - i += 1; - } - } - - Err(err) => println!("Failed to parse: {}", err), - } - } - Err(ReadlineError::Interrupted) => { - continue; - } - Err(ReadlineError::Eof) => { - break; - } - Err(err) => { - println!("Error: {:?}", err); - } - } - } // loop - Ok(()) -} - -fn main() -> Result<()> { +use std::path::Path; +use rustyline::config::Configurer; +use rustyline::Editor; +use rustyline::highlight::MatchingBracketHighlighter; +use rustyline::validate::MatchingBracketValidator; +use cas3::{Context2, ReplHelper, run_file, startup_attrs}; + +fn main() -> rustyline::Result<()> { let h = ReplHelper { highlighter: MatchingBracketHighlighter::new(), colored_prompt: "".to_owned(), @@ -1612,540 +31,4 @@ fn main() -> Result<()> { run(rl, ctx)?; Ok(()) -} - -pub fn evalparse(s: &str) -> Expr { - let ex = expr_parser::Expr(s); - match ex { - Ok(expr) => { - let mut ctx = Context2 { - vars: HashMap::new(), - }; - let mut stack = Expr::List(vec![]); - evaluate(&mut stack, &mut ctx, &expr) - } - Err(err) => panic!("Failed to parse: {s}: {err}"), - } -} - -pub fn ctx_evalparse(ctx: &mut Context2, s: &str) -> Expr { - let ex = expr_parser::Expr(s); - match ex { - Ok(expr) => { - let mut stack = Expr::List(vec![]); - evaluate(&mut stack, ctx, &expr) - } - Err(err) => panic!("Failed to parse: {s}: {err}"), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parser() { - assert_eq!(parse("(f (* *hi* *) x)"), parse("(f x)")); - } - - #[test] - fn test_pattern_matching() { - assert_eq!(evalparse("(matchq 1 (blank))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (blank Int))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (pattern x (blank)))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (pattern x (blank Int)))"), sym("true")); - assert_eq!( - evalparse("(matchq 1 (pattern x (blank Sym)))"), - sym("false") - ); - assert_eq!( - evalparse("(matchq ((k a) b) ((k (pattern x (blank Sym))) (pattern y (blank Sym))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq ((k a) b) ((k (pattern x (blank))) (pattern y (blank))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq (plus 1 2) (plus (blank) (blank)))"), - sym("true") - ); - - assert_eq!(evalparse("(matchq (list a b c) (blank))"), sym("true")); - assert_eq!( - evalparse("(matchq (list a b c) (pattern x (blank)))"), - sym("true") - ); - - assert_eq!(evalparse("(matchq (f (g 1)) (f (g (blank))))"), sym("true")); - - // testing that patterns with the same name must equal the same matched expr - assert_eq!( - evalparse("(matchq (f a a) (f (pattern x (blank)) (pattern x (blank))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq (f a b) (f (pattern x (blank)) (pattern x (blank))))"), - sym("false") - ); - - // nested patterns, head is pattern - assert_eq!( - evalparse("(matchq (foo x) ((pattern f (blank)) (pattern y (blank))))"), - sym("true") - ); - - // head matching - assert_eq!( - evalparse("(matchq (list x) (pattern x (blank list)))"), - sym("true") - ); - - // blank doesnt match the here, which is correct. triple_blank would match this - assert_eq!(evalparse("(matchq (f) (f (blank)))"), sym("false")); - } - - #[test] - fn test_rules_and_replacement() { - assert_eq!( - evalparse("(replace ((k a) b) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"), - sym("a") - ); - - // list of rules does first one that matches - assert_eq!( - evalparse("(replace x (List (rule a b) (rule x y)))"), - sym("y") - ); - assert_eq!( - evalparse("(replace x (List (rule x y) (rule x z)))"), - sym("y") - ); - - // doesn't keep going - assert_eq!( - evalparse("(replace x (List (rule x y) (rule y z)))"), - sym("y") - ); - - // case where no rules apply - assert_eq!( - evalparse("(replace_all x (List (rule y a) (rule z b)))"), - sym("x") - ); - - // test for blank with head + nested List - assert_eq!( - evalparse(r#"(replace_all (List 1 1.5 Pi (List a 2)) (rule (blank Int) "hi"))"#), - expr_parser::Expr(r#"(List "hi" 1.5 Pi (List a "hi"))"#).unwrap() - ); - - assert_eq!( - evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1)))"), - expr_parser::Expr("(List 1 (power 1 2) y z)").unwrap() - ); - - assert_eq!( - evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1) (rule y 2)))"), - expr_parser::Expr("(List 1 (power 1 2) 2 z)").unwrap() - ); - - assert_eq!( - evalparse("(replace_all (plus 1 (pow x 2) (pow x 4)) (rule (pow x (pattern p (blank))) (f p)))"), - expr_parser::Expr("(plus 1 (f 2) (f 4))").unwrap() - ); - - let s = "(replace_repeated (List (f (f x)) (f x) (g (f x)) (f (g (f x)))) (List (rule (f (pattern x (blank))) x)))"; - // todo test s above to give (List x x (g x) (g x)) - assert_eq!( - evalparse(s), - expr_parser::Expr("(List x x (g x) (g x))").unwrap() - ); - // (s k) is false, and k is true - // Combinator reduction of And for Tuples[{True, False}] - // in boolean logic, you need 3 things to "do everything" - // true, false, nand - // whats cool about combinators, is you only need 2 things - // s and k combinators. everything else is up to interpretation - - let test_cases = vec![ - ("((((s s) k) (s k)) (s k))", "(s k)"), - ("((((s s) k) (s k)) k)", "(s k)"), - ("((((s s) k) k) (s k))", "(s k)"), - ("((((s s) k) k) k)", "k"), - ]; - let crules_str = "(List (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"; - for (input, res) in test_cases.iter() { - assert_eq!( - evalparse(&format!("(rr {} {crules_str})", input)), - expr_parser::Expr(res).unwrap() - ); - } - - // let nand = "s[ s[ k[ s[ s[ s][s[k[k[k]]]]]]]][s]"; - // (s (s (k (s (s s) (s (k (k k))))))) - - // let nand = "(((s s) (s (k (k k)))) s)"; - // let nand = "(((s s) (s (k (k k)))) s)"; - // let nand = "(s (s (k (s (((s s) (s (k (k k)))))))) s)"; - // let nand = "(((s (s (k (((s (s s)) (s (k (k k)))))))) s)"; - // let a = "k"; - // let b = "k"; - // let s = format!("(({nand} {a}) {b})"); - // println!("{}", s); - } - - #[test] - fn list_ops() { - assert_eq!( - evalparse("(sameq (Part (f x y z) (List 1 2 3)) (List x y z))"), - sym("true") - ); - } - - #[test] - fn seqs_and_geeks() { - assert_eq!( - evalparse("(sameq (f (Sequence a b) c (Sequence d e)) (f a b c d e))"), - sym("true") - ); - - let mut ctx = Context2 { - vars: HashMap::new(), - }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - ctx_evalparse( - &mut ctx, - "(setd (listq (pattern x (blank))) (sameq list (head x)))", - ); - println!("listq ctx {:?}", ctx); - assert_eq!(ctx_evalparse(&mut ctx, "(listq (list a b c))"), sym("true")); - - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); - // issue #2 - assert_eq!( - ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), - sym("true") - ) - } - - #[test] - fn new_pattern_matcher() { - let blank = list(vec!["blank"]); - - let lhs = list(vec!["f", "a", "b"]); - let rhs = list(vec!["f", "blank"]); - - let test_cases = vec![ - (sym("1"), sym("1"), true), // goes to "1" == "1" Sym, Sym arm - (sym("1"), blank.clone(), true), // Sym Sym arm with blank - (sym("1"), Expr::List(vec![sym("1")]), false), // Sym List -> false - (Expr::List(vec![sym("1")]), sym("1"), false), // List Sym - // (1) | (blank) - (Expr::List(vec![sym("1")]), blank.clone(), true), // List, sym, with blank - (lhs.clone(), rhs.clone(), false), // List, sym, with blank - // (lhs.clone(), list(vec!["f", "blank", "blank"]), true), // List, sym, with blank - ( - lhs.clone(), - liste(vec![sym("f"), blank.clone(), blank.clone()]), - true, - ), // List, sym, with blank - (sym("f"), list(vec!["blank", "Sym"]), true), - (sym("f"), list(vec!["blank", "f"]), false), - (list(vec!["f", "x"]), list(vec!["blank", "f"]), true), - (list(vec!["f", "x"]), list(vec!["blank", "g"]), false), - (parse("(f (a b))"), parse("(f (blank))"), true), - (parse("(f (a b))"), parse("(f (blank a))"), true), - (parse("(f x)"), parse("((blank) (blank))"), true), - (parse("f"), parse("(pattern x (blank))"), true), - (parse("(f)"), parse("(pattern x (blank))"), true), - (parse("(f x)"), parse("((pattern x (blank)) (blank))"), true), - ( - parse("(f a b c)"), - parse("(f (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a b c)"), - parse("(f (pattern x (blank_seq)) (pattern y (blank_seq)))"), - true, - ), - ( - parse("(f a a)"), - parse("(f (pattern x (blank_seq)) (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a (g b))"), - parse("(f (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a)"), - parse("(f (pattern x (blank_null_seq)))"), - true, - ), - ( - parse("(f a)"), - parse("(f (pattern x (blank_null_seq)) a)"), - true, - ), - ( - parse("(f a b c a b)"), - parse("(f (pattern x (blank_seq)) c (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f (a b) c a b)"), - parse("(f (pattern x (blank b)) (pattern y (blank_seq)))"), - false, - ), - ( - parse("(f (a b) c a b)"), - parse("(f (pattern x (blank a)) (pattern y (blank_seq)))"), - true, - ), - ( - parse("(f a b c d)"), - parse("(f (blank_seq) (pattern y (blank_seq)))"), - true, - ), - // fails todo fix blank_seq with head - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (pattern x (blank_seq a)))"), - false, - ), - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (pattern x (blank_seq a)) (b d))"), - true, - ), - // pos : Vec where are we in the pattern Expr - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (blank_seq a) (b d))"), - true, - ), - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (blank_seq a))"), - false, - ), - ]; - - // list(vec!["f", "a", "b", "c"]), list(vec!["f", sym("blank_sequence")]) - for (i, (ex, pat, expected)) in test_cases.iter().enumerate() { - println!("testing case {i}: {ex} | {pat} "); - let pos = vec![]; - let mut pos_map = HashMap::new(); - let mut named_map = HashMap::new(); - let m = my_match(ex.clone(), pat.clone(), &pos, &mut pos_map, &mut named_map); - let rebuilt_ex = final_rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); - // let rebuilt_ex = rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); - println!("rebuilt:{rebuilt_ex:?}\n\npos:\n{pos_map:?}\nnamed:\n{named_map:?}\n\n"); - - assert_eq!(m, *expected); - - if *expected { - assert_eq!(rebuilt_ex, ex.clone()); - } - } - } - - /// https://github.com/anandijain/cas3.rs/issues/1 - #[test] - fn issue_1() { - assert_eq!( - evalparse("(matchq (f a b 0 c) (f (blank_seq) 0 (blank_seq)))"), - sym("true") - ) - } - #[test] - fn table_tests() { - let mut ctx = Context2 { - vars: HashMap::new(), - }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - ctx_evalparse(&mut ctx, "(set xs (List 1 2 3 4 5))"); - - let cases = vec![ - ("(Table f 3)", "(List f f f)"), - ("(Table i (List i 3))", "(List 1 2 3)"), - ("(Table i (List i 2 4))", "(List 2 3 4)"), - ("(Table i (List i 1 6 2))", "(List 1 3 5)"), - ("(Table i (List i (List 1.5 3.5)))", "(List 1.5 3.5)"), - ( - "(Table (List i j) (List i 2) (List j 2))", - "(List (List (List 1 1) (List 1 2)) (List (List 2 1) (List 2 2)))", - ), - ( - "(Table (Part xs (List i (Plus i 1) (Plus i 2))) (List i (Plus (Length xs) -2)))", - "(List (List 1 2 3) (List 2 3 4) (List 3 4 5))", - ), - ]; - for (lhs, rhs) in cases { - let res = ctx_evalparse(&mut ctx, lhs); - assert_eq!(res, expr_parser::Expr(rhs).unwrap()); - } - } - - #[test] - fn issue_2() { - let mut ctx = Context2 { - vars: HashMap::new(), - }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); - assert_eq!( - ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), - sym("true") - ) - } - - #[test] - fn alternatives_test() { - let mut ctx = Context2 { - vars: HashMap::new(), - }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); - let cases = vec![ - ("(matchq a (Alternatives a b))", sym("true")), - ("(matchq (f a) (f (Alternatives a b)))", sym("true")), - ( - "(matchq (f a b c) (Alternatives a (f (blank_seq))))", - sym("true"), - ), - ( - "(matchq (f a b c) (Alternatives a (f (pattern xs (blank_seq)))))", - sym("true"), - ), - ( - "(matchq (f a b c) (Alternatives a (f (blank_seq))))", - sym("true"), - ), - ( - "(matchq (f) (Alternatives a (f (blank_seq))))", - sym("false"), - ), - // ("(matchq a (Alternatives a b))", sym("true")), - ]; - - for (c, e) in cases { - assert_eq!(ctx_evalparse(&mut ctx, c), e) - } - } -} - -/* -exprs/programs to make work -1. - -(set x 1) -x -(set y 2) -(+ x y) => (+ 1 2). I don't think i want/need to implement arithmetic yet -2. -k[x_][y_] := x -(SetDelayed (k (pattern x (blank)) (pattern y (blank))) x) - -f[x_] := {x, x^2, x^3} -f[y] # gives {x, x^2, x^3} -(SetDelayed (f (pattern x (blank)) (list x (pow x 2) (pow x 3))) - -3. -(matchq x x) # true -(matchq x y) # false -(matchq x (pattern (blank))) # true -(matchq (list a) (pattern (blank))) # true - -4. (most important right now) -SetDelayed[fib[Pattern[n, Blank[]]], Plus[fib[Plus[n, -1]], fib[Plus[n, -2]]]]] - -(set (fib 1) (fib 0)) -(set (fib 0) 1) -(set_delayed (fib (pattern n (blank))) (plus (fib (minus n 1)) (fib (minus n 2)))) -(set_delayed (fib (pattern n (blank Int))) (plus (fib (minus n 1)) (fib (minus n 2)))) -(fib 5) - -okay so we make a new hashmap called DownValues that is a HashMap of symbol to list of exprs -this list of expr is all the downvalues. -so -f[x_][y_] := x -f[x_] := 1 - -f[x][y] # 1 - -k[x_][y_] := x -k[x][y] # x - -so it does the recursive thing, doesn't find any pattern matching (k x), which it looks to find first, shown by the f example -then goes out to see if there is a more nested pattern that matches, which is the k example - - -one thing that mathematica does is it actually stores (fib 2, 3,... ) in the evaluation of fib(5) - - -notes: -currently this crashes the interpreter because it goes into an infinite loop (no fixed point) -(set (f) (f f) -(set (f f) (f)) - -f[x_] := x -f[1] - -(setd (f (pattern x (blank))) (f x)) -(f 1) so basically wh - -(f (list 1)) - - ------- -TODO actually make testing - -(set (a b) c) -(a b) == c -(set b 1) -(a b) == (a 1) - ------- -need to make -(set x (plus x 1)) -crash the program -and -(setd x (plus x 1)) not -but (setd x (plus x 1)), (x) should crash the program - - - -f[x_]:=g[y_]:=y -f[1] === Null # True -but note that if you try to call g before f, then g is undefined -so -ff[x_]:=gg[y_]:=y -gg[1] # gives gg[1] -but then -ff[1] -gg[1] # now gives 1 - -also note that -x=1 -x=2 -works because Set is HoldFirst - - -https://mathematica.stackexchange.com/questions/176732/can-a-symbol-have-more-than-one-ownvalue -i will keep TableEntry.own as a list expr, but since I am not going to do conditional evaluation, it will only have one element -if set manually by the user, through OwnValues[x] = ..., i panic if more than one - -one interesting thing is how to set Set attributes to HoldFirst and Setd before calling Set and Setd. -maybe have to manually put in those DownValues of Attributes manually in rust and not in startup -can also just hardcode it in evaluate to never evaluate the first argument of Set and the rest - - -apply just replaces list with arg[1] -apply[f, {a, b, c}] # f[a, b, c] - - -*/ +} \ No newline at end of file diff --git a/projects/cas3-jupyter/Cargo.toml b/projects/cas3-jupyter/Cargo.toml index f09a59f..31cce45 100644 --- a/projects/cas3-jupyter/Cargo.toml +++ b/projects/cas3-jupyter/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" exclude = ["package.json", "tests/**"] [[bin]] -name = "jupyter-valkyrie" +name = "jupyter-cas3" path = "src/main.rs" [dependencies] @@ -28,9 +28,9 @@ version = "0.2.1" version = "0.0.2" #path = "C:\\Users\\Dell\\CLionProjects\\jupyter-protocol\\projects\\jupyter-derive" -[dependencies.valkyrie-interpreter] -version = "0.0.*" -path = "../valkyrie-interpreter" +[dependencies.cas3] +version = "0.1.*" +path = "../cas3-core" [dev-dependencies] tokio = "1.32.0" From 4b7693ef7827cdb6488166a6f8c7ecde6fbed015 Mon Sep 17 00:00:00 2001 From: Aster Date: Fri, 10 Nov 2023 22:18:49 +0000 Subject: [PATCH 3/8] split jupyter and repl into different front ends --- projects/cas3-core/Cargo.toml | 2 +- projects/cas3-repl/Cargo.toml | 18 ++++ projects/cas3-repl/lang/aliases.sexp | 4 + projects/cas3-repl/lang/attrs.sexp | 11 ++ projects/cas3-repl/lang/calculus.sexp | 41 +++++++ projects/cas3-repl/lang/startup.sexp | 102 ++++++++++++++++++ projects/cas3-repl/lang/systems.sexp | 47 ++++++++ projects/cas3-repl/src/lib.rs | 0 projects/{cas3-core => cas3-repl}/src/main.rs | 2 +- 9 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 projects/cas3-repl/Cargo.toml create mode 100644 projects/cas3-repl/lang/aliases.sexp create mode 100644 projects/cas3-repl/lang/attrs.sexp create mode 100644 projects/cas3-repl/lang/calculus.sexp create mode 100644 projects/cas3-repl/lang/startup.sexp create mode 100644 projects/cas3-repl/lang/systems.sexp create mode 100644 projects/cas3-repl/src/lib.rs rename projects/{cas3-core => cas3-repl}/src/main.rs (94%) diff --git a/projects/cas3-core/Cargo.toml b/projects/cas3-core/Cargo.toml index 90fb288..d9e3b7d 100644 --- a/projects/cas3-core/Cargo.toml +++ b/projects/cas3-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cas3" +name = "cas3-core" version = "0.1.0" edition = "2021" diff --git a/projects/cas3-repl/Cargo.toml b/projects/cas3-repl/Cargo.toml new file mode 100644 index 0000000..83344e5 --- /dev/null +++ b/projects/cas3-repl/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cas3" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +#cairo-rs = { version = "0.18.2", features = ["svg"] } +num-bigint = "0.4.4" +num-traits = "0.2.17" +ordered-float = "4.1.0" +peg = "0.8.1" +rustyline = { version = "12.0.0", features = ["derive", "custom-bindings"] } + +[dependencies.cas3-core] +version = "0.1.*" +path = "../cas3-core" diff --git a/projects/cas3-repl/lang/aliases.sexp b/projects/cas3-repl/lang/aliases.sexp new file mode 100644 index 0000000..ddefdd4 --- /dev/null +++ b/projects/cas3-repl/lang/aliases.sexp @@ -0,0 +1,4 @@ +(set ra replace_all) +(set rr replace_repeated) +(set list List) +(set alts Alternatives) \ No newline at end of file diff --git a/projects/cas3-repl/lang/attrs.sexp b/projects/cas3-repl/lang/attrs.sexp new file mode 100644 index 0000000..5523be5 --- /dev/null +++ b/projects/cas3-repl/lang/attrs.sexp @@ -0,0 +1,11 @@ +(set (attrs setd) (list HoldAll SequenceHold)) +(set (attrs clear) (list HoldAll)) +(set (attrs hold) (list HoldAll)) +(set (attrs pattern) (list HoldFirst)) + +(set (attrs true) (list locked protected)) +(set (attrs false) (list locked protected)) + +(set (attrs rule) (list SequenceHold)) +(set (attrs Table) (list HoldAll)) +(set (attrs Timing) (list HoldAll)) diff --git a/projects/cas3-repl/lang/calculus.sexp b/projects/cas3-repl/lang/calculus.sexp new file mode 100644 index 0000000..af9f270 --- /dev/null +++ b/projects/cas3-repl/lang/calculus.sexp @@ -0,0 +1,41 @@ +(setd (D (pattern c (blank Int)) (pattern x (blank Sym))) 0) +(setd (D (pattern c (blank Real)) (pattern x (blank Sym))) 0) + +(setd (D (pattern x (blank Sym)) (pattern x (blank Sym))) 1) + +(setd (D (Times (pattern a (blank Int)) (pattern x (blank Sym))) (pattern x (blank Sym))) a) +(setd (D (Times (pattern a (blank Real)) (pattern x (blank Sym))) (pattern x (blank Sym))) a) + +(setd (D (Times (pattern x (blank Sym)) (pattern a (blank Int))) (pattern x (blank Sym))) a) +(setd (D (Times (pattern x (blank Sym)) (pattern a (blank Real))) (pattern x (blank Sym))) a) + +(setd (D (Plus + (pattern expr1 (blank)) + (pattern expr2 (blank))) + (pattern x (blank Sym))) + (Plus (D expr1 x) (D expr2 x))) + +(setd (D (Times + (pattern expr1 (blank)) + (pattern expr2 (blank))) + (pattern x (blank Sym))) + (Plus (Times expr1 (D expr2 x)) (Times expr2 (D expr1 x)))) + +(setd (D (Power + (pattern expr1 (blank)) + (pattern n (blank Int))) + (pattern x (blank Sym))) + (Times n (Power expr1 (Plus n -1)) (D expr1 x))) + +(setd (D (Exp + (pattern expr (blank))) + (pattern x (blank Sym))) + (Times (D expr x) (Exp expr))) + +(setd (D (Sin + (pattern expr (blank))) + (pattern x (blank Sym))) + (Times (D expr x) (Cos expr))) + + +(setd (D (Cos (pattern expr (blank))) (pattern x (blank Sym))) (Times (Times -1 (D expr x)) (Sin expr))) diff --git a/projects/cas3-repl/lang/startup.sexp b/projects/cas3-repl/lang/startup.sexp new file mode 100644 index 0000000..47a861b --- /dev/null +++ b/projects/cas3-repl/lang/startup.sexp @@ -0,0 +1,102 @@ +(* bool *) +(set (And true true) true) +(set (And true false) false) +(set (And false true) false) +(set (And false false) false) + +(set (Or true true) true) +(set (Or true false) true) +(set (Or false true) true) +(set (Or false false) false) + +(set (Xor true true) false) +(set (Xor true false) true) +(set (Xor false true) true) +(set (Xor false false) false) + +(set (Nand true true) false) +(set (Nand true false) true) +(set (Nand false true) true) +(set (Nand false false) true) + +(set (Not true) false) +(set (Not false) true) + +(set (Not (Not (pattern x (blank)))) x) + +(setd (If true (pattern x (blank)) (pattern y (blank))) x) +(setd (If false (pattern x (blank)) (pattern y (blank))) y) + +(setd (If true (pattern x (blank))) x) +(setd (If false (pattern x (blank))) Null) + +(setd (If true (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) x) +(setd (If false (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) y) +(setd (If (pattern t (blank)) (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) z) + +(* (setd (Boole 0) false) +(setd (Boole 1) true) *) + +(* Identity laws for addition *) +(* Adding 0 to any number results in the number itself *) +(setd (Plus (pattern x (blank)) 0) x) +(setd (Plus 0 (pattern x (blank))) x) + +(* Identity laws for multiplication *) +(* Multiplying any number by 1 results in the number itself *) +(setd (Times (pattern x (blank)) 1) x) +(setd (Times 1 (pattern x (blank))) x) + +(* Absorbing laws for multiplication *) +(* Multiplying any number by 0 results in 0 *) +(* (setd (Times (pattern x (blank)) 0) 0) *) +(* (setd (Times 0 (pattern x (blank))) 0) *) +(setd (Times (pattern xs (blank_null_seq)) 0 (pattern ys (blank_null_seq))) 0) +(setd (Times (pattern xs (blank_null_seq)) 1 (pattern ys (blank_null_seq))) (Times xs ys)) + + +(* Identity laws for exponentiation *) +(* Raising any number to the power of 1 results in the number itself *) +(* Raising any number to the power of 0 results in 1 *) +(setd (Power (pattern x (blank)) 1) x) +(setd (Power (pattern x (blank)) 0) 1) + +(setd (Nest (pattern f (blank)) (pattern x (blank)) 0) x) +(setd (Nest (pattern f (blank)) (pattern x (blank)) (pattern n (blank Int))) (f (Nest f x (Plus n -1)))) + +(set (Fac 1) 1) +(set (Fac (pattern n (blank Int))) (Times n (Fac (Plus n -1)))) + +(setd (First (List (pattern x (blank)) (pattern rest (blank_null_seq)))) x) +(setd (First (pattern xs (blank_null_seq))) (First (List xs))) +(setd (Rest (List (blank) (pattern rest (blank_null_seq)))) (List rest)) +(setd (Rest (pattern xs (blank_null_seq))) (Rest (List xs))) + +(* note this definition is different than wolfram which gives some "Identity[a,b,c]" and a warning *) +(set (to_seq (List (pattern xs (blank_null_seq)))) xs) + +(* broken, implemented kernel side for now *) +(* (setd (Map (pattern f (blank)) (list)) (list)) *) +(* (setd (Map (pattern f (blank)) (list (pattern xs (blank_seq)))) (list (f (First xs)) (to_seq (Map f (Rest (list xs)))))) *) + +(setd (ListQ (pattern x (blank))) (sameq list (head x))) + +(setd (Succ (pattern n (blank Int))) (Plus n 1)) + +(* works but is not that general *) +(* for example *) + +(* Range[x, x + 4] *) +(* Range[1.2, 2.2, 0.15] *) +(setd (Range (pattern n (blank Int))) (Table i (List i n))) +(setd (Range + (pattern imin (blank Int)) + (pattern imax (blank Int)) + ) (Table i (List i imin imax))) + +(setd (Range + (pattern imin (blank Int)) + (pattern imax (blank Int)) + (pattern di (blank Int)) + ) (Table i (List i imin imax di))) + diff --git a/projects/cas3-repl/lang/systems.sexp b/projects/cas3-repl/lang/systems.sexp new file mode 100644 index 0000000..a99ec52 --- /dev/null +++ b/projects/cas3-repl/lang/systems.sexp @@ -0,0 +1,47 @@ +(* combinators *) +(set sk_rules + (list + (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) + (rule ((k (pattern x (blank))) (pattern y (blank))) + x))) + +(set succ (s ((s (k s)) k))) +(setd (skn (pattern n (blank Int))) (Nest succ (s k) n)) + +(set sk_plus ((s (k s)) (s (k ((s (k s)) k))))) +(set sk_times ((s (k s)) k)) +(set sk_pow ((s (k (s ((s k) k)))) k)) + +(* CA *) +(set (rule_30 (pattern p (blank)) (pattern r (blank)) (pattern q (blank))) (Xor p (Or r q))) + +(setd (rule_30 + (List + (pattern p (blank)) + (pattern r (blank)) + (pattern q (blank)))) + (Xor p (Or r q))) + +(* (setd (pad_zero (pattern xs (blank List))) (Join (List 0) xs (List 0))) +(setd (idxs (pattern n (blank Int))) (Table (Plus i n_) (List n_ 0 n))) *) + +(setd (pad_val + (pattern xs (blank List)) + (pattern val (blank))) + (Join (List val) xs (List val))) + +(setd (lil_partition3 + (pattern xs (blank List))) + (Table (List (Part xs i) (Part xs (Plus i 1)) (Part xs (Plus i 2))) (List i (Plus (Length xs) -2)) + )) + +(setd (foo (pattern xs (blank List))) + (Map rule_30 (lil_partition3 (pad_val xs false)))) + +(set u0 (replace_all (List 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (List (rule 0 false) (rule 1 true)))) + +(set ls (replace_all (NestList foo u0 20) (List (rule false 0) (rule true 1)))) + +(* rendering *) +(set ps (replace_all ls (List (rule 0 (List 1. 1. 1.)) (rule 1 (List 0. 0. 0.))))) +(Export "rule_30.svg" ps) diff --git a/projects/cas3-repl/src/lib.rs b/projects/cas3-repl/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/projects/cas3-core/src/main.rs b/projects/cas3-repl/src/main.rs similarity index 94% rename from projects/cas3-core/src/main.rs rename to projects/cas3-repl/src/main.rs index 59fc3f3..8914e0d 100644 --- a/projects/cas3-core/src/main.rs +++ b/projects/cas3-repl/src/main.rs @@ -4,7 +4,7 @@ use rustyline::config::Configurer; use rustyline::Editor; use rustyline::highlight::MatchingBracketHighlighter; use rustyline::validate::MatchingBracketValidator; -use cas3::{Context2, ReplHelper, run_file, startup_attrs}; +use cas3::{Context2, ReplHelper, run, run_file, startup_attrs}; fn main() -> rustyline::Result<()> { let h = ReplHelper { From 0263a338b038cbb5c69cf639f8b83bb3fbe2f8cc Mon Sep 17 00:00:00 2001 From: Aster Date: Fri, 10 Nov 2023 23:28:28 +0000 Subject: [PATCH 4/8] define the common execution environment `Cas3VM` --- Cargo.lock | 14 +- projects/cas3-core/src/lib.rs | 153 ++++++++++------------ projects/cas3-jupyter/Cargo.toml | 2 +- projects/cas3-jupyter/src/config/mod.rs | 6 +- projects/cas3-jupyter/src/executor/mod.rs | 16 +-- projects/cas3-jupyter/src/main.rs | 4 +- projects/cas3-jupyter/src/protocol/mod.rs | 4 +- projects/cas3-repl/src/main.rs | 12 +- 8 files changed, 100 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 110ae0e..00f4781 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,18 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cas3" version = "0.1.0" +dependencies = [ + "cas3-core", + "num-bigint", + "num-traits", + "ordered-float", + "peg", + "rustyline", +] + +[[package]] +name = "cas3-core" +version = "0.1.0" dependencies = [ "num-bigint", "num-traits", @@ -201,7 +213,7 @@ name = "cas3-jupyter" version = "0.0.0" dependencies = [ "async-trait", - "cas3", + "cas3-core", "clap", "jupyter", "jupyter-derive", diff --git a/projects/cas3-core/src/lib.rs b/projects/cas3-core/src/lib.rs index 2fe9661..58bb688 100644 --- a/projects/cas3-core/src/lib.rs +++ b/projects/cas3-core/src/lib.rs @@ -1,5 +1,6 @@ // extern crate cairo; extern crate peg; + use std::{ borrow::Cow::{self, Borrowed, Owned}, ops::{Add, Mul}, @@ -152,9 +153,9 @@ pub fn is_atom(expr: &Expr) -> bool { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Context2 { - pub vars: HashMap, +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct Cas3VM { + vars: HashMap, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -174,7 +175,7 @@ impl TableEntry { } } -pub fn get_ownvalue(ctx: &Context2, sym: Expr) -> Option { +pub fn get_ownvalue(ctx: &Cas3VM, sym: Expr) -> Option { // println!("ctx: {:?}. sym: {}", ctx, sym); let te = ctx.vars.get(&sym); if let Some(te) = te { @@ -264,7 +265,7 @@ fn unpack_mat(ex: Expr) -> Option>> { // nh can be List too pub fn internal_functions_apply( stack: &mut Expr, - ctx: &mut Context2, + ctx: &mut Cas3VM, nh: Expr, evaluated_args: Vec, ) -> Expr { @@ -286,7 +287,7 @@ pub fn internal_functions_apply( evaluated_args[1].clone(), &vec![], &mut HashMap::new(), - &mut HashMap::new() + &mut HashMap::new(), ) )); } else if nh == sym("sameq") { @@ -526,7 +527,7 @@ pub fn internal_functions_apply( return length(&evaluated_args[0]); } else if nh == sym("Get") { if let Expr::Str(p) = &evaluated_args[0] { - let res = run_file(ctx, Path::new(&p)); + let res = ctx.run_file(p); if let Ok(res) = res { return res; } else { @@ -677,10 +678,10 @@ pub fn internal_functions_apply( } let range_lists = &evaluated_args[1..]; //.clone().reverse(); - // Table[ f[i,j], {i, imin, imax}, {j, jmin, jmax}] - // Table[Table[f[i,j], {j, jmin, jmax}], {i, imin, imax}] - // let mut ex = Expr::List(vec![sym("Table")]); - // ex.push(table_body.clone()); + // Table[ f[i,j], {i, imin, imax}, {j, jmin, jmax}] + // Table[Table[f[i,j], {j, jmin, jmax}], {i, imin, imax}] + // let mut ex = Expr::List(vec![sym("Table")]); + // ex.push(table_body.clone()); let mut nested_table = table_body.clone(); for range in range_lists.iter().rev() { @@ -753,7 +754,7 @@ pub fn internal_functions_apply( } } -pub fn evaluate(stack: &mut Expr, ctx: &mut Context2, expr: &Expr) -> Expr { +pub fn evaluate(stack: &mut Expr, ctx: &mut Cas3VM, expr: &Expr) -> Expr { let mut ex = expr.clone(); let mut last_ex = None; @@ -1450,7 +1451,7 @@ pub fn replace_repeated(expr: &Expr, rules: &Expr) -> Expr { current_expr } -pub fn startup_attrs(ctx: &mut Context2) { +pub fn startup_attrs(ctx: &mut Cas3VM) { let attrs_te = ctx.vars.entry(sym("attrs")).or_insert_with(TableEntry::new); let mut exs = vec![ format!("(rule_delayed (hold_pattern (attrs hold_pattern)) (list HoldAll))"), @@ -1459,15 +1460,15 @@ pub fn startup_attrs(ctx: &mut Context2) { format!("(rule_delayed (hold_pattern (attrs set)) (list HoldFirst SequenceHold))"), format!("(rule_delayed (hold_pattern (attrs down_values)) (list HoldAll))"), ] - .iter_mut() - .map(|s| expr_parser::Expr(&s).unwrap()) - .collect(); + .iter_mut() + .map(|s| expr_parser::Expr(&s).unwrap()) + .collect(); attrs_te.down.append(&mut exs); } #[derive(Helper, Completer, Hinter, Validator)] pub struct ReplHelper { - pub highlighter: MatchingBracketHighlighter, + pub highlighter: MatchingBracketHighlighter, #[rustyline(Validator)] pub validator: MatchingBracketValidator, pub colored_prompt: String, @@ -1499,41 +1500,45 @@ impl Highlighter for ReplHelper { } } -pub fn run_file(ctx: &mut Context2, filepath: &Path) -> Result { - // let file = File::open(filepath)?; - // let reader = BufReader::new(file); - let file_contents = std::fs::read_to_string(filepath)?; - // i dont love this because it's ambigious whether or not something failed in reading the file or sth - // or if the last expr in the file was a setd or something that returns a Null - println!("Running file: {}", filepath.display()); - let mut res = sym("Null"); - let exprs = expr_parser::expressions(&file_contents).unwrap(); - // for line in reader.lines() { - for expr in exprs { - // match line { - // Ok(content) => { - // if content.starts_with("//") || content.starts_with(";") || content.is_empty() { - // continue; - // } - // if let Ok(ex) = &expr_parser::Expr(&content) { - let mut stack = Expr::List(vec![]); - res = evaluate(&mut stack, ctx, &expr); - // } else { - // eprintln!("Error parsing a line: {:?}", content); +impl Cas3VM { + pub fn run_file>(&mut self, filepath: P) -> Result { + let filepath = filepath.as_ref(); + // let file = File::open(filepath)?; + // let reader = BufReader::new(file); + let file_contents = std::fs::read_to_string(filepath)?; + // i dont love this because it's ambigious whether or not something failed in reading the file or sth + // or if the last expr in the file was a setd or something that returns a Null + println!("Running file: {}", filepath.display()); + let mut res = sym("Null"); + let exprs = expr_parser::expressions(&file_contents).unwrap(); + // for line in reader.lines() { + for expr in exprs { + // match line { + // Ok(content) => { + // if content.starts_with("//") || content.starts_with(";") || content.is_empty() { + // continue; + // } + // if let Ok(ex) = &expr_parser::Expr(&content) { + let mut stack = Expr::List(vec![]); + res = evaluate(&mut stack, self, &expr); + // } else { + // eprintln!("Error parsing a line: {:?}", content); + // } + } + // Err(error) => { + // eprintln!("Error reading a line: {:?}", error); + // } + // } // } - } - // Err(error) => { - // eprintln!("Error reading a line: {:?}", error); - // } - // } - // } - Ok(res) + Ok(res) + } } + pub fn run( mut rl: rustyline::Editor, - mut ctx: Context2, + mut ctx: Cas3VM, ) -> Result<()> { let mut i = 1; @@ -1545,7 +1550,7 @@ pub fn run( match line { Ok(l) => { rl.add_history_entry(l.as_str()).unwrap(); // history - // saving every line (even if slow, just until its more stable) + // saving every line (even if slow, just until its more stable) rl.save_history("history.txt").unwrap(); let exs = expr_parser::expressions(&l); @@ -1587,38 +1592,11 @@ pub fn run( Ok(()) } -fn main() -> Result<()> { - let h = ReplHelper { - highlighter: MatchingBracketHighlighter::new(), - colored_prompt: "".to_owned(), - validator: MatchingBracketValidator::new(), - }; - let config = rustyline::Config::default(); - let mut rl = Editor::with_config(config)?; - rl.set_max_history_size(10000).unwrap(); - rl.set_helper(Some(h)); - if rl.load_history("history.txt").is_err() { - println!("No previous history."); - } - let mut ctx = Context2 { - vars: HashMap::new(), - }; - - startup_attrs(&mut ctx); - run_file(&mut ctx, Path::new("lang/attrs.sexp"))?; - run_file(&mut ctx, Path::new("lang/startup.sexp"))?; - run_file(&mut ctx, Path::new("lang/calculus.sexp"))?; - // run_file(&mut ctx, Path::new("lang/systems.sexp"))?; - - run(rl, ctx)?; - Ok(()) -} - pub fn evalparse(s: &str) -> Expr { let ex = expr_parser::Expr(s); match ex { Ok(expr) => { - let mut ctx = Context2 { + let mut ctx = Cas3VM { vars: HashMap::new(), }; let mut stack = Expr::List(vec![]); @@ -1628,7 +1606,7 @@ pub fn evalparse(s: &str) -> Expr { } } -pub fn ctx_evalparse(ctx: &mut Context2, s: &str) -> Expr { +pub fn ctx_evalparse(ctx: &mut Cas3VM, s: &str) -> Expr { let ex = expr_parser::Expr(s); match ex { Ok(expr) => { @@ -1810,10 +1788,10 @@ mod tests { sym("true") ); - let mut ctx = Context2 { + let mut ctx = Cas3VM { vars: HashMap::new(), }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); ctx_evalparse( &mut ctx, "(setd (listq (pattern x (blank))) (sameq list (head x)))", @@ -1821,7 +1799,7 @@ mod tests { println!("listq ctx {:?}", ctx); assert_eq!(ctx_evalparse(&mut ctx, "(listq (list a b c))"), sym("true")); - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); // issue #2 assert_eq!( ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), @@ -1961,12 +1939,13 @@ mod tests { sym("true") ) } + #[test] fn table_tests() { - let mut ctx = Context2 { + let mut ctx = Cas3VM { vars: HashMap::new(), }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); ctx_evalparse(&mut ctx, "(set xs (List 1 2 3 4 5))"); let cases = vec![ @@ -1992,11 +1971,11 @@ mod tests { #[test] fn issue_2() { - let mut ctx = Context2 { + let mut ctx = Cas3VM { vars: HashMap::new(), }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); assert_eq!( ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), sym("true") @@ -2005,11 +1984,11 @@ mod tests { #[test] fn alternatives_test() { - let mut ctx = Context2 { + let mut ctx = Cas3VM { vars: HashMap::new(), }; - run_file(&mut ctx, Path::new("lang/attrs.sexp")).unwrap(); - run_file(&mut ctx, Path::new("lang/startup.sexp")).unwrap(); + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); let cases = vec![ ("(matchq a (Alternatives a b))", sym("true")), ("(matchq (f a) (f (Alternatives a b)))", sym("true")), diff --git a/projects/cas3-jupyter/Cargo.toml b/projects/cas3-jupyter/Cargo.toml index 31cce45..aa5b08f 100644 --- a/projects/cas3-jupyter/Cargo.toml +++ b/projects/cas3-jupyter/Cargo.toml @@ -28,7 +28,7 @@ version = "0.2.1" version = "0.0.2" #path = "C:\\Users\\Dell\\CLionProjects\\jupyter-protocol\\projects\\jupyter-derive" -[dependencies.cas3] +[dependencies.cas3-core] version = "0.1.*" path = "../cas3-core" diff --git a/projects/cas3-jupyter/src/config/mod.rs b/projects/cas3-jupyter/src/config/mod.rs index fd1543c..0b0105f 100644 --- a/projects/cas3-jupyter/src/config/mod.rs +++ b/projects/cas3-jupyter/src/config/mod.rs @@ -1,10 +1,10 @@ -pub struct ValkyrieConfig { +pub struct Cas3Config { pub running_time: bool, pub image_max_pixel: usize, } -impl Default for ValkyrieConfig { +impl Default for Cas3Config { fn default() -> Self { - ValkyrieConfig { running_time: false, image_max_pixel: 1024 * 768 } + Cas3Config { running_time: false, image_max_pixel: 1024 * 768 } } } diff --git a/projects/cas3-jupyter/src/executor/mod.rs b/projects/cas3-jupyter/src/executor/mod.rs index 66b3df0..30d41a2 100644 --- a/projects/cas3-jupyter/src/executor/mod.rs +++ b/projects/cas3-jupyter/src/executor/mod.rs @@ -1,20 +1,20 @@ -use crate::{config::ValkyrieConfig, DisplayKeywords, DisplayNumber}; +use crate::{config::Cas3Config}; use jupyter::{to_value, value_type::HtmlText, ExecutionRequest, JupyterError, JupyterKernelSockets, JupyterMessage}; -use valkyrie_interpreter::{ValkyrieError, ValkyrieVM, ValkyrieValue}; +use cas3_core::Cas3VM; -pub struct ValkyrieExecutor { - pub(crate) vm: ValkyrieVM, +pub struct CasExecutor { + pub(crate) vm: Cas3VM, pub(crate) sockets: JupyterKernelSockets, - pub(crate) config: ValkyrieConfig, + pub(crate) config: Cas3Config, } -impl Default for ValkyrieExecutor { +impl Default for CasExecutor { fn default() -> Self { - ValkyrieExecutor { vm: ValkyrieVM::default(), sockets: Default::default(), config: ValkyrieConfig::default() } + CasExecutor { vm: Cas3VM::default(), sockets: Default::default(), config: Cas3Config::default() } } } -impl ValkyrieExecutor { +impl CasExecutor { pub(crate) async fn repl_parse_and_run(&mut self, code: &ExecutionRequest) -> Result<(), ValkyrieError> { let file = self.vm.load_snippet(&code.code, &format!("Cell{}", code.execution_count)); for task in self.vm.execute_script(file).await { diff --git a/projects/cas3-jupyter/src/main.rs b/projects/cas3-jupyter/src/main.rs index 3920ca0..9a5367c 100644 --- a/projects/cas3-jupyter/src/main.rs +++ b/projects/cas3-jupyter/src/main.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Formatter}; use std::path::PathBuf; -use crate::executor::ValkyrieExecutor; +use crate::executor::CasExecutor; use clap::{Parser, Subcommand}; use jupyter::{InstallAction, JupyterResult, OpenAction, StartAction, UninstallAction}; use std::io::Write; @@ -52,7 +52,7 @@ impl Debug for JupyterCommands { impl JupyterApplication { /// Run the application pub fn run(&self) -> JupyterResult<()> { - let config = ValkyrieExecutor::default(); + let config = CasExecutor::default(); match &self.command { JupyterCommands::Open(v) => v.run(), JupyterCommands::Start(v) => v.run(config), diff --git a/projects/cas3-jupyter/src/protocol/mod.rs b/projects/cas3-jupyter/src/protocol/mod.rs index 88d99a0..846b791 100644 --- a/projects/cas3-jupyter/src/protocol/mod.rs +++ b/projects/cas3-jupyter/src/protocol/mod.rs @@ -1,4 +1,4 @@ -use crate::executor::ValkyrieExecutor; +use crate::executor::CasExecutor; use jupyter::{ value_type::{JupyterContext, JupyterTheme}, Executed, ExecutionReply, ExecutionRequest, JupyterConnection, JupyterError, JupyterKernelProtocol, LanguageInfo, Value, @@ -7,7 +7,7 @@ use jupyter_derive::include_png32; pub mod display; -impl JupyterKernelProtocol for ValkyrieExecutor { +impl JupyterKernelProtocol for CasExecutor { fn language_info(&self) -> LanguageInfo { let mut info = LanguageInfo::new("valkyrie", "Valkyrie").with_syntax("scala", "scala").with_version(env!("CARGO_PKG_VERSION")); diff --git a/projects/cas3-repl/src/main.rs b/projects/cas3-repl/src/main.rs index 8914e0d..5706cdf 100644 --- a/projects/cas3-repl/src/main.rs +++ b/projects/cas3-repl/src/main.rs @@ -4,7 +4,7 @@ use rustyline::config::Configurer; use rustyline::Editor; use rustyline::highlight::MatchingBracketHighlighter; use rustyline::validate::MatchingBracketValidator; -use cas3::{Context2, ReplHelper, run, run_file, startup_attrs}; +use cas3_core::{Cas3VM, ReplHelper, run, startup_attrs}; fn main() -> rustyline::Result<()> { let h = ReplHelper { @@ -19,14 +19,12 @@ fn main() -> rustyline::Result<()> { if rl.load_history("history.txt").is_err() { println!("No previous history."); } - let mut ctx = Context2 { - vars: HashMap::new(), - }; + let mut ctx = Cas3VM::default(); startup_attrs(&mut ctx); - run_file(&mut ctx, Path::new("lang/attrs.sexp"))?; - run_file(&mut ctx, Path::new("lang/startup.sexp"))?; - run_file(&mut ctx, Path::new("lang/calculus.sexp"))?; + ctx.run_file("lang/attrs.sexp")?; + ctx.run_file("lang/startup.sexp")?; + ctx.run_file("lang/calculus.sexp")?; // run_file(&mut ctx, Path::new("lang/systems.sexp"))?; run(rl, ctx)?; From d58b1747f4d0fdbad24ef3a7057fc2773bfbf803 Mon Sep 17 00:00:00 2001 From: Aster Date: Sat, 11 Nov 2023 04:19:29 +0000 Subject: [PATCH 5/8] use centralized error management --- Cargo.lock | 1 - projects/cas3-core/Cargo.toml | 1 - projects/cas3-core/lang/aliases.sexp | 4 - projects/cas3-core/lang/attrs.sexp | 11 - projects/cas3-core/lang/calculus.sexp | 41 -- projects/cas3-core/lang/startup.sexp | 102 ---- projects/cas3-core/lang/systems.sexp | 47 -- projects/cas3-core/src/errors/mod.rs | 33 ++ projects/cas3-core/src/lib.rs | 625 +--------------------- projects/cas3-core/src/tests.rs | 509 ++++++++++++++++++ projects/cas3-core/tests/main.rs | 0 projects/cas3-jupyter/src/executor/mod.rs | 49 +- projects/cas3-repl/src/lib.rs | 97 ++++ projects/cas3-repl/src/main.rs | 13 +- 14 files changed, 664 insertions(+), 869 deletions(-) delete mode 100644 projects/cas3-core/lang/aliases.sexp delete mode 100644 projects/cas3-core/lang/attrs.sexp delete mode 100644 projects/cas3-core/lang/calculus.sexp delete mode 100644 projects/cas3-core/lang/startup.sexp delete mode 100644 projects/cas3-core/lang/systems.sexp create mode 100644 projects/cas3-core/src/errors/mod.rs create mode 100644 projects/cas3-core/src/tests.rs create mode 100644 projects/cas3-core/tests/main.rs diff --git a/Cargo.lock b/Cargo.lock index 00f4781..a1f9a29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,7 +205,6 @@ dependencies = [ "num-traits", "ordered-float", "peg", - "rustyline", ] [[package]] diff --git a/projects/cas3-core/Cargo.toml b/projects/cas3-core/Cargo.toml index d9e3b7d..4fb7383 100644 --- a/projects/cas3-core/Cargo.toml +++ b/projects/cas3-core/Cargo.toml @@ -11,4 +11,3 @@ num-bigint = "0.4.4" num-traits = "0.2.17" ordered-float = "4.1.0" peg = "0.8.1" -rustyline = { version = "12.0.0", features = ["derive", "custom-bindings"] } diff --git a/projects/cas3-core/lang/aliases.sexp b/projects/cas3-core/lang/aliases.sexp deleted file mode 100644 index ddefdd4..0000000 --- a/projects/cas3-core/lang/aliases.sexp +++ /dev/null @@ -1,4 +0,0 @@ -(set ra replace_all) -(set rr replace_repeated) -(set list List) -(set alts Alternatives) \ No newline at end of file diff --git a/projects/cas3-core/lang/attrs.sexp b/projects/cas3-core/lang/attrs.sexp deleted file mode 100644 index 5523be5..0000000 --- a/projects/cas3-core/lang/attrs.sexp +++ /dev/null @@ -1,11 +0,0 @@ -(set (attrs setd) (list HoldAll SequenceHold)) -(set (attrs clear) (list HoldAll)) -(set (attrs hold) (list HoldAll)) -(set (attrs pattern) (list HoldFirst)) - -(set (attrs true) (list locked protected)) -(set (attrs false) (list locked protected)) - -(set (attrs rule) (list SequenceHold)) -(set (attrs Table) (list HoldAll)) -(set (attrs Timing) (list HoldAll)) diff --git a/projects/cas3-core/lang/calculus.sexp b/projects/cas3-core/lang/calculus.sexp deleted file mode 100644 index af9f270..0000000 --- a/projects/cas3-core/lang/calculus.sexp +++ /dev/null @@ -1,41 +0,0 @@ -(setd (D (pattern c (blank Int)) (pattern x (blank Sym))) 0) -(setd (D (pattern c (blank Real)) (pattern x (blank Sym))) 0) - -(setd (D (pattern x (blank Sym)) (pattern x (blank Sym))) 1) - -(setd (D (Times (pattern a (blank Int)) (pattern x (blank Sym))) (pattern x (blank Sym))) a) -(setd (D (Times (pattern a (blank Real)) (pattern x (blank Sym))) (pattern x (blank Sym))) a) - -(setd (D (Times (pattern x (blank Sym)) (pattern a (blank Int))) (pattern x (blank Sym))) a) -(setd (D (Times (pattern x (blank Sym)) (pattern a (blank Real))) (pattern x (blank Sym))) a) - -(setd (D (Plus - (pattern expr1 (blank)) - (pattern expr2 (blank))) - (pattern x (blank Sym))) - (Plus (D expr1 x) (D expr2 x))) - -(setd (D (Times - (pattern expr1 (blank)) - (pattern expr2 (blank))) - (pattern x (blank Sym))) - (Plus (Times expr1 (D expr2 x)) (Times expr2 (D expr1 x)))) - -(setd (D (Power - (pattern expr1 (blank)) - (pattern n (blank Int))) - (pattern x (blank Sym))) - (Times n (Power expr1 (Plus n -1)) (D expr1 x))) - -(setd (D (Exp - (pattern expr (blank))) - (pattern x (blank Sym))) - (Times (D expr x) (Exp expr))) - -(setd (D (Sin - (pattern expr (blank))) - (pattern x (blank Sym))) - (Times (D expr x) (Cos expr))) - - -(setd (D (Cos (pattern expr (blank))) (pattern x (blank Sym))) (Times (Times -1 (D expr x)) (Sin expr))) diff --git a/projects/cas3-core/lang/startup.sexp b/projects/cas3-core/lang/startup.sexp deleted file mode 100644 index 47a861b..0000000 --- a/projects/cas3-core/lang/startup.sexp +++ /dev/null @@ -1,102 +0,0 @@ -(* bool *) -(set (And true true) true) -(set (And true false) false) -(set (And false true) false) -(set (And false false) false) - -(set (Or true true) true) -(set (Or true false) true) -(set (Or false true) true) -(set (Or false false) false) - -(set (Xor true true) false) -(set (Xor true false) true) -(set (Xor false true) true) -(set (Xor false false) false) - -(set (Nand true true) false) -(set (Nand true false) true) -(set (Nand false true) true) -(set (Nand false false) true) - -(set (Not true) false) -(set (Not false) true) - -(set (Not (Not (pattern x (blank)))) x) - -(setd (If true (pattern x (blank)) (pattern y (blank))) x) -(setd (If false (pattern x (blank)) (pattern y (blank))) y) - -(setd (If true (pattern x (blank))) x) -(setd (If false (pattern x (blank))) Null) - -(setd (If true (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) x) -(setd (If false (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) y) -(setd (If (pattern t (blank)) (pattern x (blank)) (pattern y (blank)) (pattern z (blank))) z) - -(* (setd (Boole 0) false) -(setd (Boole 1) true) *) - -(* Identity laws for addition *) -(* Adding 0 to any number results in the number itself *) -(setd (Plus (pattern x (blank)) 0) x) -(setd (Plus 0 (pattern x (blank))) x) - -(* Identity laws for multiplication *) -(* Multiplying any number by 1 results in the number itself *) -(setd (Times (pattern x (blank)) 1) x) -(setd (Times 1 (pattern x (blank))) x) - -(* Absorbing laws for multiplication *) -(* Multiplying any number by 0 results in 0 *) -(* (setd (Times (pattern x (blank)) 0) 0) *) -(* (setd (Times 0 (pattern x (blank))) 0) *) -(setd (Times (pattern xs (blank_null_seq)) 0 (pattern ys (blank_null_seq))) 0) -(setd (Times (pattern xs (blank_null_seq)) 1 (pattern ys (blank_null_seq))) (Times xs ys)) - - -(* Identity laws for exponentiation *) -(* Raising any number to the power of 1 results in the number itself *) -(* Raising any number to the power of 0 results in 1 *) -(setd (Power (pattern x (blank)) 1) x) -(setd (Power (pattern x (blank)) 0) 1) - -(setd (Nest (pattern f (blank)) (pattern x (blank)) 0) x) -(setd (Nest (pattern f (blank)) (pattern x (blank)) (pattern n (blank Int))) (f (Nest f x (Plus n -1)))) - -(set (Fac 1) 1) -(set (Fac (pattern n (blank Int))) (Times n (Fac (Plus n -1)))) - -(setd (First (List (pattern x (blank)) (pattern rest (blank_null_seq)))) x) -(setd (First (pattern xs (blank_null_seq))) (First (List xs))) -(setd (Rest (List (blank) (pattern rest (blank_null_seq)))) (List rest)) -(setd (Rest (pattern xs (blank_null_seq))) (Rest (List xs))) - -(* note this definition is different than wolfram which gives some "Identity[a,b,c]" and a warning *) -(set (to_seq (List (pattern xs (blank_null_seq)))) xs) - -(* broken, implemented kernel side for now *) -(* (setd (Map (pattern f (blank)) (list)) (list)) *) -(* (setd (Map (pattern f (blank)) (list (pattern xs (blank_seq)))) (list (f (First xs)) (to_seq (Map f (Rest (list xs)))))) *) - -(setd (ListQ (pattern x (blank))) (sameq list (head x))) - -(setd (Succ (pattern n (blank Int))) (Plus n 1)) - -(* works but is not that general *) -(* for example *) - -(* Range[x, x + 4] *) -(* Range[1.2, 2.2, 0.15] *) -(setd (Range (pattern n (blank Int))) (Table i (List i n))) -(setd (Range - (pattern imin (blank Int)) - (pattern imax (blank Int)) - ) (Table i (List i imin imax))) - -(setd (Range - (pattern imin (blank Int)) - (pattern imax (blank Int)) - (pattern di (blank Int)) - ) (Table i (List i imin imax di))) - diff --git a/projects/cas3-core/lang/systems.sexp b/projects/cas3-core/lang/systems.sexp deleted file mode 100644 index a99ec52..0000000 --- a/projects/cas3-core/lang/systems.sexp +++ /dev/null @@ -1,47 +0,0 @@ -(* combinators *) -(set sk_rules - (list - (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) - (rule ((k (pattern x (blank))) (pattern y (blank))) - x))) - -(set succ (s ((s (k s)) k))) -(setd (skn (pattern n (blank Int))) (Nest succ (s k) n)) - -(set sk_plus ((s (k s)) (s (k ((s (k s)) k))))) -(set sk_times ((s (k s)) k)) -(set sk_pow ((s (k (s ((s k) k)))) k)) - -(* CA *) -(set (rule_30 (pattern p (blank)) (pattern r (blank)) (pattern q (blank))) (Xor p (Or r q))) - -(setd (rule_30 - (List - (pattern p (blank)) - (pattern r (blank)) - (pattern q (blank)))) - (Xor p (Or r q))) - -(* (setd (pad_zero (pattern xs (blank List))) (Join (List 0) xs (List 0))) -(setd (idxs (pattern n (blank Int))) (Table (Plus i n_) (List n_ 0 n))) *) - -(setd (pad_val - (pattern xs (blank List)) - (pattern val (blank))) - (Join (List val) xs (List val))) - -(setd (lil_partition3 - (pattern xs (blank List))) - (Table (List (Part xs i) (Part xs (Plus i 1)) (Part xs (Plus i 2))) (List i (Plus (Length xs) -2)) - )) - -(setd (foo (pattern xs (blank List))) - (Map rule_30 (lil_partition3 (pad_val xs false)))) - -(set u0 (replace_all (List 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (List (rule 0 false) (rule 1 true)))) - -(set ls (replace_all (NestList foo u0 20) (List (rule false 0) (rule true 1)))) - -(* rendering *) -(set ps (replace_all ls (List (rule 0 (List 1. 1. 1.)) (rule 1 (List 0. 0. 0.))))) -(Export "rule_30.svg" ps) diff --git a/projects/cas3-core/src/errors/mod.rs b/projects/cas3-core/src/errors/mod.rs new file mode 100644 index 0000000..294c634 --- /dev/null +++ b/projects/cas3-core/src/errors/mod.rs @@ -0,0 +1,33 @@ +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub struct Cas3Error { + kind: Box, +} + +#[derive(Debug)] +pub enum Cas3ErrorKind { + IoError(std::io::Error) +} + +impl Display for Cas3ErrorKind { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Cas3ErrorKind::IoError(v) => { + write!(f, "IO Error: {}", v) + } + } + } +} + + +impl Display for Cas3Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.kind) + } +} + +impl Error for Cas3Error {} \ No newline at end of file diff --git a/projects/cas3-core/src/lib.rs b/projects/cas3-core/src/lib.rs index 58bb688..9105701 100644 --- a/projects/cas3-core/src/lib.rs +++ b/projects/cas3-core/src/lib.rs @@ -2,31 +2,25 @@ extern crate peg; use std::{ - borrow::Cow::{self, Borrowed, Owned}, ops::{Add, Mul}, }; +use std::{fmt, path::Path}; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; +use std::time::Instant; -use ordered_float::{self, NotNan}; // use rug::Integer; // use num_bigint::BigInt; use num_traits::cast::ToPrimitive; - +use ordered_float::{self, NotNan}; // use cairo::{Context, SvgSurface}; -use rustyline::{ - config::Configurer, - error::ReadlineError, - highlight::{Highlighter, MatchingBracketHighlighter}, - validate::MatchingBracketValidator, - Completer, Editor, Helper, Hinter, Result, Validator, -}; -use std::collections::HashMap; -use std::ops::{Deref, DerefMut}; -use std::time::{Duration, Instant}; -use std::{fmt, path::Path}; +#[cfg(test)] +mod tests; +mod errors; peg::parser! { - grammar expr_parser() for str { + pub grammar expr_parser() for str { rule comment() = "(*" (!"*)" [_])* "*)" @@ -1466,42 +1460,8 @@ pub fn startup_attrs(ctx: &mut Cas3VM) { attrs_te.down.append(&mut exs); } -#[derive(Helper, Completer, Hinter, Validator)] -pub struct ReplHelper { - pub highlighter: MatchingBracketHighlighter, - #[rustyline(Validator)] - pub validator: MatchingBracketValidator, - pub colored_prompt: String, -} - -impl Highlighter for ReplHelper { - fn highlight_prompt<'b, 's: 'b, 'p: 'b>( - &'s self, - prompt: &'p str, - default: bool, - ) -> Cow<'b, str> { - if default { - Borrowed(&self.colored_prompt) - } else { - Borrowed(prompt) - } - } - - fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { - Owned("\x1b[1m".to_owned() + hint + "\x1b[m") - } - - fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { - self.highlighter.highlight(line, pos) - } - - fn highlight_char(&self, line: &str, pos: usize) -> bool { - self.highlighter.highlight_char(line, pos) - } -} - impl Cas3VM { - pub fn run_file>(&mut self, filepath: P) -> Result { + pub fn run_file>(&mut self, filepath: P) -> std::io::Result { let filepath = filepath.as_ref(); // let file = File::open(filepath)?; // let reader = BufReader::new(file); @@ -1536,61 +1496,7 @@ impl Cas3VM { } -pub fn run( - mut rl: rustyline::Editor, - mut ctx: Cas3VM, -) -> Result<()> { - let mut i = 1; - - loop { - let prompt = format!("(In {}) := ", i); - rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{prompt}\x1b[0m"); - - let line = rl.readline(&prompt); // read - match line { - Ok(l) => { - rl.add_history_entry(l.as_str()).unwrap(); // history - // saving every line (even if slow, just until its more stable) - rl.save_history("history.txt").unwrap(); - - let exs = expr_parser::expressions(&l); - - match exs { - Ok(exprs) => { - for expr in exprs { - let mut stack = Expr::List(vec![]); - let res = evaluate(&mut stack, &mut ctx, &expr); - let in_i = - expr_parser::Expr(format!("(setd (In {i}) {})", expr).as_str()) - .unwrap(); - evaluate(&mut stack, &mut ctx, &in_i); - let out_i = - expr_parser::Expr(format!("(set (Out {i}) {})", res).as_str()) - .unwrap(); - evaluate(&mut stack, &mut ctx, &out_i); - - println!("\x1B[1m(Out {i}) = {}\x1B[0m", res); - i += 1; - } - } - - Err(err) => println!("Failed to parse: {}", err), - } - } - Err(ReadlineError::Interrupted) => { - continue; - } - Err(ReadlineError::Eof) => { - break; - } - Err(err) => { - println!("Error: {:?}", err); - } - } - } // loop - Ok(()) -} pub fn evalparse(s: &str) -> Expr { let ex = expr_parser::Expr(s); @@ -1617,514 +1523,3 @@ pub fn ctx_evalparse(ctx: &mut Cas3VM, s: &str) -> Expr { } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parser() { - assert_eq!(parse("(f (* *hi* *) x)"), parse("(f x)")); - } - - #[test] - fn test_pattern_matching() { - assert_eq!(evalparse("(matchq 1 (blank))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (blank Int))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (pattern x (blank)))"), sym("true")); - assert_eq!(evalparse("(matchq 1 (pattern x (blank Int)))"), sym("true")); - assert_eq!( - evalparse("(matchq 1 (pattern x (blank Sym)))"), - sym("false") - ); - assert_eq!( - evalparse("(matchq ((k a) b) ((k (pattern x (blank Sym))) (pattern y (blank Sym))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq ((k a) b) ((k (pattern x (blank))) (pattern y (blank))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq (plus 1 2) (plus (blank) (blank)))"), - sym("true") - ); - - assert_eq!(evalparse("(matchq (list a b c) (blank))"), sym("true")); - assert_eq!( - evalparse("(matchq (list a b c) (pattern x (blank)))"), - sym("true") - ); - - assert_eq!(evalparse("(matchq (f (g 1)) (f (g (blank))))"), sym("true")); - - // testing that patterns with the same name must equal the same matched expr - assert_eq!( - evalparse("(matchq (f a a) (f (pattern x (blank)) (pattern x (blank))))"), - sym("true") - ); - assert_eq!( - evalparse("(matchq (f a b) (f (pattern x (blank)) (pattern x (blank))))"), - sym("false") - ); - - // nested patterns, head is pattern - assert_eq!( - evalparse("(matchq (foo x) ((pattern f (blank)) (pattern y (blank))))"), - sym("true") - ); - - // head matching - assert_eq!( - evalparse("(matchq (list x) (pattern x (blank list)))"), - sym("true") - ); - - // blank doesnt match the here, which is correct. triple_blank would match this - assert_eq!(evalparse("(matchq (f) (f (blank)))"), sym("false")); - } - - #[test] - fn test_rules_and_replacement() { - assert_eq!( - evalparse("(replace ((k a) b) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"), - sym("a") - ); - - // list of rules does first one that matches - assert_eq!( - evalparse("(replace x (List (rule a b) (rule x y)))"), - sym("y") - ); - assert_eq!( - evalparse("(replace x (List (rule x y) (rule x z)))"), - sym("y") - ); - - // doesn't keep going - assert_eq!( - evalparse("(replace x (List (rule x y) (rule y z)))"), - sym("y") - ); - - // case where no rules apply - assert_eq!( - evalparse("(replace_all x (List (rule y a) (rule z b)))"), - sym("x") - ); - - // test for blank with head + nested List - assert_eq!( - evalparse(r#"(replace_all (List 1 1.5 Pi (List a 2)) (rule (blank Int) "hi"))"#), - expr_parser::Expr(r#"(List "hi" 1.5 Pi (List a "hi"))"#).unwrap() - ); - - assert_eq!( - evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1)))"), - expr_parser::Expr("(List 1 (power 1 2) y z)").unwrap() - ); - - assert_eq!( - evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1) (rule y 2)))"), - expr_parser::Expr("(List 1 (power 1 2) 2 z)").unwrap() - ); - - assert_eq!( - evalparse("(replace_all (plus 1 (pow x 2) (pow x 4)) (rule (pow x (pattern p (blank))) (f p)))"), - expr_parser::Expr("(plus 1 (f 2) (f 4))").unwrap() - ); - - let s = "(replace_repeated (List (f (f x)) (f x) (g (f x)) (f (g (f x)))) (List (rule (f (pattern x (blank))) x)))"; - // todo test s above to give (List x x (g x) (g x)) - assert_eq!( - evalparse(s), - expr_parser::Expr("(List x x (g x) (g x))").unwrap() - ); - // (s k) is false, and k is true - // Combinator reduction of And for Tuples[{True, False}] - // in boolean logic, you need 3 things to "do everything" - // true, false, nand - // whats cool about combinators, is you only need 2 things - // s and k combinators. everything else is up to interpretation - - let test_cases = vec![ - ("((((s s) k) (s k)) (s k))", "(s k)"), - ("((((s s) k) (s k)) k)", "(s k)"), - ("((((s s) k) k) (s k))", "(s k)"), - ("((((s s) k) k) k)", "k"), - ]; - let crules_str = "(List (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"; - for (input, res) in test_cases.iter() { - assert_eq!( - evalparse(&format!("(rr {} {crules_str})", input)), - expr_parser::Expr(res).unwrap() - ); - } - - // let nand = "s[ s[ k[ s[ s[ s][s[k[k[k]]]]]]]][s]"; - // (s (s (k (s (s s) (s (k (k k))))))) - - // let nand = "(((s s) (s (k (k k)))) s)"; - // let nand = "(((s s) (s (k (k k)))) s)"; - // let nand = "(s (s (k (s (((s s) (s (k (k k)))))))) s)"; - // let nand = "(((s (s (k (((s (s s)) (s (k (k k)))))))) s)"; - // let a = "k"; - // let b = "k"; - // let s = format!("(({nand} {a}) {b})"); - // println!("{}", s); - } - - #[test] - fn list_ops() { - assert_eq!( - evalparse("(sameq (Part (f x y z) (List 1 2 3)) (List x y z))"), - sym("true") - ); - } - - #[test] - fn seqs_and_geeks() { - assert_eq!( - evalparse("(sameq (f (Sequence a b) c (Sequence d e)) (f a b c d e))"), - sym("true") - ); - - let mut ctx = Cas3VM { - vars: HashMap::new(), - }; - ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); - ctx_evalparse( - &mut ctx, - "(setd (listq (pattern x (blank))) (sameq list (head x)))", - ); - println!("listq ctx {:?}", ctx); - assert_eq!(ctx_evalparse(&mut ctx, "(listq (list a b c))"), sym("true")); - - ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); - // issue #2 - assert_eq!( - ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), - sym("true") - ) - } - - #[test] - fn new_pattern_matcher() { - let blank = list(vec!["blank"]); - - let lhs = list(vec!["f", "a", "b"]); - let rhs = list(vec!["f", "blank"]); - - let test_cases = vec![ - (sym("1"), sym("1"), true), // goes to "1" == "1" Sym, Sym arm - (sym("1"), blank.clone(), true), // Sym Sym arm with blank - (sym("1"), Expr::List(vec![sym("1")]), false), // Sym List -> false - (Expr::List(vec![sym("1")]), sym("1"), false), // List Sym - // (1) | (blank) - (Expr::List(vec![sym("1")]), blank.clone(), true), // List, sym, with blank - (lhs.clone(), rhs.clone(), false), // List, sym, with blank - // (lhs.clone(), list(vec!["f", "blank", "blank"]), true), // List, sym, with blank - ( - lhs.clone(), - liste(vec![sym("f"), blank.clone(), blank.clone()]), - true, - ), // List, sym, with blank - (sym("f"), list(vec!["blank", "Sym"]), true), - (sym("f"), list(vec!["blank", "f"]), false), - (list(vec!["f", "x"]), list(vec!["blank", "f"]), true), - (list(vec!["f", "x"]), list(vec!["blank", "g"]), false), - (parse("(f (a b))"), parse("(f (blank))"), true), - (parse("(f (a b))"), parse("(f (blank a))"), true), - (parse("(f x)"), parse("((blank) (blank))"), true), - (parse("f"), parse("(pattern x (blank))"), true), - (parse("(f)"), parse("(pattern x (blank))"), true), - (parse("(f x)"), parse("((pattern x (blank)) (blank))"), true), - ( - parse("(f a b c)"), - parse("(f (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a b c)"), - parse("(f (pattern x (blank_seq)) (pattern y (blank_seq)))"), - true, - ), - ( - parse("(f a a)"), - parse("(f (pattern x (blank_seq)) (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a (g b))"), - parse("(f (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f a)"), - parse("(f (pattern x (blank_null_seq)))"), - true, - ), - ( - parse("(f a)"), - parse("(f (pattern x (blank_null_seq)) a)"), - true, - ), - ( - parse("(f a b c a b)"), - parse("(f (pattern x (blank_seq)) c (pattern x (blank_seq)))"), - true, - ), - ( - parse("(f (a b) c a b)"), - parse("(f (pattern x (blank b)) (pattern y (blank_seq)))"), - false, - ), - ( - parse("(f (a b) c a b)"), - parse("(f (pattern x (blank a)) (pattern y (blank_seq)))"), - true, - ), - ( - parse("(f a b c d)"), - parse("(f (blank_seq) (pattern y (blank_seq)))"), - true, - ), - // fails todo fix blank_seq with head - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (pattern x (blank_seq a)))"), - false, - ), - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (pattern x (blank_seq a)) (b d))"), - true, - ), - // pos : Vec where are we in the pattern Expr - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (blank_seq a) (b d))"), - true, - ), - ( - parse("(f (a b) (a c) (b d))"), - parse("(f (blank_seq a))"), - false, - ), - ]; - - // list(vec!["f", "a", "b", "c"]), list(vec!["f", sym("blank_sequence")]) - for (i, (ex, pat, expected)) in test_cases.iter().enumerate() { - println!("testing case {i}: {ex} | {pat} "); - let pos = vec![]; - let mut pos_map = HashMap::new(); - let mut named_map = HashMap::new(); - let m = my_match(ex.clone(), pat.clone(), &pos, &mut pos_map, &mut named_map); - let rebuilt_ex = final_rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); - // let rebuilt_ex = rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); - println!("rebuilt:{rebuilt_ex:?}\n\npos:\n{pos_map:?}\nnamed:\n{named_map:?}\n\n"); - - assert_eq!(m, *expected); - - if *expected { - assert_eq!(rebuilt_ex, ex.clone()); - } - } - } - - /// https://github.com/anandijain/cas3.rs/issues/1 - #[test] - fn issue_1() { - assert_eq!( - evalparse("(matchq (f a b 0 c) (f (blank_seq) 0 (blank_seq)))"), - sym("true") - ) - } - - #[test] - fn table_tests() { - let mut ctx = Cas3VM { - vars: HashMap::new(), - }; - ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); - ctx_evalparse(&mut ctx, "(set xs (List 1 2 3 4 5))"); - - let cases = vec![ - ("(Table f 3)", "(List f f f)"), - ("(Table i (List i 3))", "(List 1 2 3)"), - ("(Table i (List i 2 4))", "(List 2 3 4)"), - ("(Table i (List i 1 6 2))", "(List 1 3 5)"), - ("(Table i (List i (List 1.5 3.5)))", "(List 1.5 3.5)"), - ( - "(Table (List i j) (List i 2) (List j 2))", - "(List (List (List 1 1) (List 1 2)) (List (List 2 1) (List 2 2)))", - ), - ( - "(Table (Part xs (List i (Plus i 1) (Plus i 2))) (List i (Plus (Length xs) -2)))", - "(List (List 1 2 3) (List 2 3 4) (List 3 4 5))", - ), - ]; - for (lhs, rhs) in cases { - let res = ctx_evalparse(&mut ctx, lhs); - assert_eq!(res, expr_parser::Expr(rhs).unwrap()); - } - } - - #[test] - fn issue_2() { - let mut ctx = Cas3VM { - vars: HashMap::new(), - }; - ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); - ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); - assert_eq!( - ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), - sym("true") - ) - } - - #[test] - fn alternatives_test() { - let mut ctx = Cas3VM { - vars: HashMap::new(), - }; - ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); - ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); - let cases = vec![ - ("(matchq a (Alternatives a b))", sym("true")), - ("(matchq (f a) (f (Alternatives a b)))", sym("true")), - ( - "(matchq (f a b c) (Alternatives a (f (blank_seq))))", - sym("true"), - ), - ( - "(matchq (f a b c) (Alternatives a (f (pattern xs (blank_seq)))))", - sym("true"), - ), - ( - "(matchq (f a b c) (Alternatives a (f (blank_seq))))", - sym("true"), - ), - ( - "(matchq (f) (Alternatives a (f (blank_seq))))", - sym("false"), - ), - // ("(matchq a (Alternatives a b))", sym("true")), - ]; - - for (c, e) in cases { - assert_eq!(ctx_evalparse(&mut ctx, c), e) - } - } -} - -/* -exprs/programs to make work -1. - -(set x 1) -x -(set y 2) -(+ x y) => (+ 1 2). I don't think i want/need to implement arithmetic yet -2. -k[x_][y_] := x -(SetDelayed (k (pattern x (blank)) (pattern y (blank))) x) - -f[x_] := {x, x^2, x^3} -f[y] # gives {x, x^2, x^3} -(SetDelayed (f (pattern x (blank)) (list x (pow x 2) (pow x 3))) - -3. -(matchq x x) # true -(matchq x y) # false -(matchq x (pattern (blank))) # true -(matchq (list a) (pattern (blank))) # true - -4. (most important right now) -SetDelayed[fib[Pattern[n, Blank[]]], Plus[fib[Plus[n, -1]], fib[Plus[n, -2]]]]] - -(set (fib 1) (fib 0)) -(set (fib 0) 1) -(set_delayed (fib (pattern n (blank))) (plus (fib (minus n 1)) (fib (minus n 2)))) -(set_delayed (fib (pattern n (blank Int))) (plus (fib (minus n 1)) (fib (minus n 2)))) -(fib 5) - -okay so we make a new hashmap called DownValues that is a HashMap of symbol to list of exprs -this list of expr is all the downvalues. -so -f[x_][y_] := x -f[x_] := 1 - -f[x][y] # 1 - -k[x_][y_] := x -k[x][y] # x - -so it does the recursive thing, doesn't find any pattern matching (k x), which it looks to find first, shown by the f example -then goes out to see if there is a more nested pattern that matches, which is the k example - - -one thing that mathematica does is it actually stores (fib 2, 3,... ) in the evaluation of fib(5) - - -notes: -currently this crashes the interpreter because it goes into an infinite loop (no fixed point) -(set (f) (f f) -(set (f f) (f)) - -f[x_] := x -f[1] - -(setd (f (pattern x (blank))) (f x)) -(f 1) so basically wh - -(f (list 1)) - - ------- -TODO actually make testing - -(set (a b) c) -(a b) == c -(set b 1) -(a b) == (a 1) - ------- -need to make -(set x (plus x 1)) -crash the program -and -(setd x (plus x 1)) not -but (setd x (plus x 1)), (x) should crash the program - - - -f[x_]:=g[y_]:=y -f[1] === Null # True -but note that if you try to call g before f, then g is undefined -so -ff[x_]:=gg[y_]:=y -gg[1] # gives gg[1] -but then -ff[1] -gg[1] # now gives 1 - -also note that -x=1 -x=2 -works because Set is HoldFirst - - -https://mathematica.stackexchange.com/questions/176732/can-a-symbol-have-more-than-one-ownvalue -i will keep TableEntry.own as a list expr, but since I am not going to do conditional evaluation, it will only have one element -if set manually by the user, through OwnValues[x] = ..., i panic if more than one - -one interesting thing is how to set Set attributes to HoldFirst and Setd before calling Set and Setd. -maybe have to manually put in those DownValues of Attributes manually in rust and not in startup -can also just hardcode it in evaluate to never evaluate the first argument of Set and the rest - - -apply just replaces list with arg[1] -apply[f, {a, b, c}] # f[a, b, c] - - -*/ diff --git a/projects/cas3-core/src/tests.rs b/projects/cas3-core/src/tests.rs new file mode 100644 index 0000000..8170a3c --- /dev/null +++ b/projects/cas3-core/src/tests.rs @@ -0,0 +1,509 @@ +use super::*; + +#[test] +fn test_parser() { + assert_eq!(parse("(f (* *hi* *) x)"), parse("(f x)")); +} + +#[test] +fn test_pattern_matching() { + assert_eq!(evalparse("(matchq 1 (blank))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (blank Int))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (pattern x (blank)))"), sym("true")); + assert_eq!(evalparse("(matchq 1 (pattern x (blank Int)))"), sym("true")); + assert_eq!( + evalparse("(matchq 1 (pattern x (blank Sym)))"), + sym("false") + ); + assert_eq!( + evalparse("(matchq ((k a) b) ((k (pattern x (blank Sym))) (pattern y (blank Sym))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq ((k a) b) ((k (pattern x (blank))) (pattern y (blank))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq (plus 1 2) (plus (blank) (blank)))"), + sym("true") + ); + + assert_eq!(evalparse("(matchq (list a b c) (blank))"), sym("true")); + assert_eq!( + evalparse("(matchq (list a b c) (pattern x (blank)))"), + sym("true") + ); + + assert_eq!(evalparse("(matchq (f (g 1)) (f (g (blank))))"), sym("true")); + + // testing that patterns with the same name must equal the same matched expr + assert_eq!( + evalparse("(matchq (f a a) (f (pattern x (blank)) (pattern x (blank))))"), + sym("true") + ); + assert_eq!( + evalparse("(matchq (f a b) (f (pattern x (blank)) (pattern x (blank))))"), + sym("false") + ); + + // nested patterns, head is pattern + assert_eq!( + evalparse("(matchq (foo x) ((pattern f (blank)) (pattern y (blank))))"), + sym("true") + ); + + // head matching + assert_eq!( + evalparse("(matchq (list x) (pattern x (blank list)))"), + sym("true") + ); + + // blank doesnt match the here, which is correct. triple_blank would match this + assert_eq!(evalparse("(matchq (f) (f (blank)))"), sym("false")); +} + +#[test] +fn test_rules_and_replacement() { + assert_eq!( + evalparse("(replace ((k a) b) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"), + sym("a") + ); + + // list of rules does first one that matches + assert_eq!( + evalparse("(replace x (List (rule a b) (rule x y)))"), + sym("y") + ); + assert_eq!( + evalparse("(replace x (List (rule x y) (rule x z)))"), + sym("y") + ); + + // doesn't keep going + assert_eq!( + evalparse("(replace x (List (rule x y) (rule y z)))"), + sym("y") + ); + + // case where no rules apply + assert_eq!( + evalparse("(replace_all x (List (rule y a) (rule z b)))"), + sym("x") + ); + + // test for blank with head + nested List + assert_eq!( + evalparse(r#"(replace_all (List 1 1.5 Pi (List a 2)) (rule (blank Int) "hi"))"#), + expr_parser::Expr(r#"(List "hi" 1.5 Pi (List a "hi"))"#).unwrap() + ); + + assert_eq!( + evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1)))"), + expr_parser::Expr("(List 1 (power 1 2) y z)").unwrap() + ); + + assert_eq!( + evalparse("(replace_all (List x (power x 2) y z) (List (rule x 1) (rule y 2)))"), + expr_parser::Expr("(List 1 (power 1 2) 2 z)").unwrap() + ); + + assert_eq!( + evalparse("(replace_all (plus 1 (pow x 2) (pow x 4)) (rule (pow x (pattern p (blank))) (f p)))"), + expr_parser::Expr("(plus 1 (f 2) (f 4))").unwrap() + ); + + let s = "(replace_repeated (List (f (f x)) (f x) (g (f x)) (f (g (f x)))) (List (rule (f (pattern x (blank))) x)))"; + // todo test s above to give (List x x (g x) (g x)) + assert_eq!( + evalparse(s), + expr_parser::Expr("(List x x (g x) (g x))").unwrap() + ); + // (s k) is false, and k is true + // Combinator reduction of And for Tuples[{True, False}] + // in boolean logic, you need 3 things to "do everything" + // true, false, nand + // whats cool about combinators, is you only need 2 things + // s and k combinators. everything else is up to interpretation + + let test_cases = vec![ + ("((((s s) k) (s k)) (s k))", "(s k)"), + ("((((s s) k) (s k)) k)", "(s k)"), + ("((((s s) k) k) (s k))", "(s k)"), + ("((((s s) k) k) k)", "k"), + ]; + let crules_str = "(List (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) (rule ((k (pattern x (blank))) (pattern y (blank))) x))"; + for (input, res) in test_cases.iter() { + assert_eq!( + evalparse(&format!("(rr {} {crules_str})", input)), + expr_parser::Expr(res).unwrap() + ); + } + + // let nand = "s[ s[ k[ s[ s[ s][s[k[k[k]]]]]]]][s]"; + // (s (s (k (s (s s) (s (k (k k))))))) + + // let nand = "(((s s) (s (k (k k)))) s)"; + // let nand = "(((s s) (s (k (k k)))) s)"; + // let nand = "(s (s (k (s (((s s) (s (k (k k)))))))) s)"; + // let nand = "(((s (s (k (((s (s s)) (s (k (k k)))))))) s)"; + // let a = "k"; + // let b = "k"; + // let s = format!("(({nand} {a}) {b})"); + // println!("{}", s); +} + +#[test] +fn list_ops() { + assert_eq!( + evalparse("(sameq (Part (f x y z) (List 1 2 3)) (List x y z))"), + sym("true") + ); +} + +#[test] +fn seqs_and_geeks() { + assert_eq!( + evalparse("(sameq (f (Sequence a b) c (Sequence d e)) (f a b c d e))"), + sym("true") + ); + + let mut ctx = Cas3VM { + vars: HashMap::new(), + }; + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx_evalparse( + &mut ctx, + "(setd (listq (pattern x (blank))) (sameq list (head x)))", + ); + println!("listq ctx {:?}", ctx); + assert_eq!(ctx_evalparse(&mut ctx, "(listq (list a b c))"), sym("true")); + + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); + // issue #2 + assert_eq!( + ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), + sym("true") + ) +} + +#[test] +fn new_pattern_matcher() { + let blank = list(vec!["blank"]); + + let lhs = list(vec!["f", "a", "b"]); + let rhs = list(vec!["f", "blank"]); + + let test_cases = vec![ + (sym("1"), sym("1"), true), // goes to "1" == "1" Sym, Sym arm + (sym("1"), blank.clone(), true), // Sym Sym arm with blank + (sym("1"), Expr::List(vec![sym("1")]), false), // Sym List -> false + (Expr::List(vec![sym("1")]), sym("1"), false), // List Sym + // (1) | (blank) + (Expr::List(vec![sym("1")]), blank.clone(), true), // List, sym, with blank + (lhs.clone(), rhs.clone(), false), // List, sym, with blank + // (lhs.clone(), list(vec!["f", "blank", "blank"]), true), // List, sym, with blank + ( + lhs.clone(), + liste(vec![sym("f"), blank.clone(), blank.clone()]), + true, + ), // List, sym, with blank + (sym("f"), list(vec!["blank", "Sym"]), true), + (sym("f"), list(vec!["blank", "f"]), false), + (list(vec!["f", "x"]), list(vec!["blank", "f"]), true), + (list(vec!["f", "x"]), list(vec!["blank", "g"]), false), + (parse("(f (a b))"), parse("(f (blank))"), true), + (parse("(f (a b))"), parse("(f (blank a))"), true), + (parse("(f x)"), parse("((blank) (blank))"), true), + (parse("f"), parse("(pattern x (blank))"), true), + (parse("(f)"), parse("(pattern x (blank))"), true), + (parse("(f x)"), parse("((pattern x (blank)) (blank))"), true), + ( + parse("(f a b c)"), + parse("(f (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a b c)"), + parse("(f (pattern x (blank_seq)) (pattern y (blank_seq)))"), + true, + ), + ( + parse("(f a a)"), + parse("(f (pattern x (blank_seq)) (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a (g b))"), + parse("(f (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f a)"), + parse("(f (pattern x (blank_null_seq)))"), + true, + ), + ( + parse("(f a)"), + parse("(f (pattern x (blank_null_seq)) a)"), + true, + ), + ( + parse("(f a b c a b)"), + parse("(f (pattern x (blank_seq)) c (pattern x (blank_seq)))"), + true, + ), + ( + parse("(f (a b) c a b)"), + parse("(f (pattern x (blank b)) (pattern y (blank_seq)))"), + false, + ), + ( + parse("(f (a b) c a b)"), + parse("(f (pattern x (blank a)) (pattern y (blank_seq)))"), + true, + ), + ( + parse("(f a b c d)"), + parse("(f (blank_seq) (pattern y (blank_seq)))"), + true, + ), + // fails todo fix blank_seq with head + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (pattern x (blank_seq a)))"), + false, + ), + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (pattern x (blank_seq a)) (b d))"), + true, + ), + // pos : Vec where are we in the pattern Expr + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (blank_seq a) (b d))"), + true, + ), + ( + parse("(f (a b) (a c) (b d))"), + parse("(f (blank_seq a))"), + false, + ), + ]; + + // list(vec!["f", "a", "b", "c"]), list(vec!["f", sym("blank_sequence")]) + for (i, (ex, pat, expected)) in test_cases.iter().enumerate() { + println!("testing case {i}: {ex} | {pat} "); + let pos = vec![]; + let mut pos_map = HashMap::new(); + let mut named_map = HashMap::new(); + let m = my_match(ex.clone(), pat.clone(), &pos, &mut pos_map, &mut named_map); + let rebuilt_ex = final_rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); + // let rebuilt_ex = rebuild_and_splice(pat.clone(), &vec![], &pos_map, &named_map); + println!("rebuilt:{rebuilt_ex:?}\n\npos:\n{pos_map:?}\nnamed:\n{named_map:?}\n\n"); + + assert_eq!(m, *expected); + + if *expected { + assert_eq!(rebuilt_ex, ex.clone()); + } + } +} + +/// https://github.com/anandijain/cas3.rs/issues/1 +#[test] +fn issue_1() { + assert_eq!( + evalparse("(matchq (f a b 0 c) (f (blank_seq) 0 (blank_seq)))"), + sym("true") + ) +} + +#[test] +fn table_tests() { + let mut ctx = Cas3VM { + vars: HashMap::new(), + }; + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx_evalparse(&mut ctx, "(set xs (List 1 2 3 4 5))"); + + let cases = vec![ + ("(Table f 3)", "(List f f f)"), + ("(Table i (List i 3))", "(List 1 2 3)"), + ("(Table i (List i 2 4))", "(List 2 3 4)"), + ("(Table i (List i 1 6 2))", "(List 1 3 5)"), + ("(Table i (List i (List 1.5 3.5)))", "(List 1.5 3.5)"), + ( + "(Table (List i j) (List i 2) (List j 2))", + "(List (List (List 1 1) (List 1 2)) (List (List 2 1) (List 2 2)))", + ), + ( + "(Table (Part xs (List i (Plus i 1) (Plus i 2))) (List i (Plus (Length xs) -2)))", + "(List (List 1 2 3) (List 2 3 4) (List 3 4 5))", + ), + ]; + for (lhs, rhs) in cases { + let res = ctx_evalparse(&mut ctx, lhs); + assert_eq!(res, expr_parser::Expr(rhs).unwrap()); + } +} + +#[test] +fn issue_2() { + let mut ctx = Cas3VM { + vars: HashMap::new(), + }; + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); + assert_eq!( + ctx_evalparse(&mut ctx, "(sameq (Nest (f) x 2) ((f) ((f) x)))"), + sym("true") + ) +} + +#[test] +fn alternatives_test() { + let mut ctx = Cas3VM { + vars: HashMap::new(), + }; + ctx.run_file( Path::new("lang/attrs.sexp")).unwrap(); + ctx.run_file( Path::new("lang/startup.sexp")).unwrap(); + let cases = vec![ + ("(matchq a (Alternatives a b))", sym("true")), + ("(matchq (f a) (f (Alternatives a b)))", sym("true")), + ( + "(matchq (f a b c) (Alternatives a (f (blank_seq))))", + sym("true"), + ), + ( + "(matchq (f a b c) (Alternatives a (f (pattern xs (blank_seq)))))", + sym("true"), + ), + ( + "(matchq (f a b c) (Alternatives a (f (blank_seq))))", + sym("true"), + ), + ( + "(matchq (f) (Alternatives a (f (blank_seq))))", + sym("false"), + ), + // ("(matchq a (Alternatives a b))", sym("true")), + ]; + + for (c, e) in cases { + assert_eq!(ctx_evalparse(&mut ctx, c), e) + } +} + + +/* +exprs/programs to make work +1. + +(set x 1) +x +(set y 2) +(+ x y) => (+ 1 2). I don't think i want/need to implement arithmetic yet +2. +k[x_][y_] := x +(SetDelayed (k (pattern x (blank)) (pattern y (blank))) x) + +f[x_] := {x, x^2, x^3} +f[y] # gives {x, x^2, x^3} +(SetDelayed (f (pattern x (blank)) (list x (pow x 2) (pow x 3))) + +3. +(matchq x x) # true +(matchq x y) # false +(matchq x (pattern (blank))) # true +(matchq (list a) (pattern (blank))) # true + +4. (most important right now) +SetDelayed[fib[Pattern[n, Blank[]]], Plus[fib[Plus[n, -1]], fib[Plus[n, -2]]]]] + +(set (fib 1) (fib 0)) +(set (fib 0) 1) +(set_delayed (fib (pattern n (blank))) (plus (fib (minus n 1)) (fib (minus n 2)))) +(set_delayed (fib (pattern n (blank Int))) (plus (fib (minus n 1)) (fib (minus n 2)))) +(fib 5) + +okay so we make a new hashmap called DownValues that is a HashMap of symbol to list of exprs +this list of expr is all the downvalues. +so +f[x_][y_] := x +f[x_] := 1 + +f[x][y] # 1 + +k[x_][y_] := x +k[x][y] # x + +so it does the recursive thing, doesn't find any pattern matching (k x), which it looks to find first, shown by the f example +then goes out to see if there is a more nested pattern that matches, which is the k example + + +one thing that mathematica does is it actually stores (fib 2, 3,... ) in the evaluation of fib(5) + + +notes: +currently this crashes the interpreter because it goes into an infinite loop (no fixed point) +(set (f) (f f) +(set (f f) (f)) + +f[x_] := x +f[1] + +(setd (f (pattern x (blank))) (f x)) +(f 1) so basically wh + +(f (list 1)) + + +------ +TODO actually make testing + +(set (a b) c) +(a b) == c +(set b 1) +(a b) == (a 1) + +------ +need to make +(set x (plus x 1)) +crash the program +and +(setd x (plus x 1)) not +but (setd x (plus x 1)), (x) should crash the program + + + +f[x_]:=g[y_]:=y +f[1] === Null # True +but note that if you try to call g before f, then g is undefined +so +ff[x_]:=gg[y_]:=y +gg[1] # gives gg[1] +but then +ff[1] +gg[1] # now gives 1 + +also note that +x=1 +x=2 +works because Set is HoldFirst + + +https://mathematica.stackexchange.com/questions/176732/can-a-symbol-have-more-than-one-ownvalue +i will keep TableEntry.own as a list expr, but since I am not going to do conditional evaluation, it will only have one element +if set manually by the user, through OwnValues[x] = ..., i panic if more than one + +one interesting thing is how to set Set attributes to HoldFirst and Setd before calling Set and Setd. +maybe have to manually put in those DownValues of Attributes manually in rust and not in startup +can also just hardcode it in evaluate to never evaluate the first argument of Set and the rest + + +apply just replaces list with arg[1] +apply[f, {a, b, c}] # f[a, b, c] + + +*/ diff --git a/projects/cas3-core/tests/main.rs b/projects/cas3-core/tests/main.rs new file mode 100644 index 0000000..e69de29 diff --git a/projects/cas3-jupyter/src/executor/mod.rs b/projects/cas3-jupyter/src/executor/mod.rs index 30d41a2..3c90837 100644 --- a/projects/cas3-jupyter/src/executor/mod.rs +++ b/projects/cas3-jupyter/src/executor/mod.rs @@ -1,6 +1,6 @@ use crate::{config::Cas3Config}; use jupyter::{to_value, value_type::HtmlText, ExecutionRequest, JupyterError, JupyterKernelSockets, JupyterMessage}; -use cas3_core::Cas3VM; +use cas3_core::{Cas3VM, Expr}; pub struct CasExecutor { pub(crate) vm: Cas3VM, @@ -26,48 +26,15 @@ impl CasExecutor { Ok(()) } - pub(crate) async fn send_value(&self, value: ValkyrieValue, parent: &JupyterMessage) { + pub(crate) async fn send_value(&self, value: Expr, parent: &JupyterMessage) { match value { - // never type never sends - ValkyrieValue::Nothing => {} - ValkyrieValue::Null => self.sockets.send_executed(DisplayKeywords::new("null"), parent).await, - ValkyrieValue::Unit => self.sockets.send_executed(DisplayKeywords::new("( )"), parent).await, - ValkyrieValue::Boolean(v) => self.sockets.send_executed(DisplayKeywords::new(v), parent).await, - ValkyrieValue::Number(v) => self.sockets.send_executed(DisplayNumber::new(v), parent).await, - ValkyrieValue::Unicode(v) => self.sockets.send_executed(v.to_string(), parent).await, - ValkyrieValue::UTF8String(v) => self.sockets.send_executed(v.get().clone(), parent).await, - ValkyrieValue::Bytes(_) => { - todo!() + Expr::Int(v) => { + self.sockets.send_executed(v.to_string(), parent).await } - ValkyrieValue::Class(_) => { - todo!() - } - ValkyrieValue::Variant(_) => { - todo!() - } - ValkyrieValue::NDArray(_) => { - todo!() - } - ValkyrieValue::Image(_) => { - todo!() - } - ValkyrieValue::Html(v) => { - self.sockets.send_executed(HtmlText::new(v), parent).await; - } - ValkyrieValue::Uninitialized => { - todo!() - } - ValkyrieValue::List(v) => match to_value(v) { - Ok(o) => self.sockets.send_executed(o, parent).await, - Err(_) => {} - }, - ValkyrieValue::Dict(v) => match to_value(v) { - Ok(o) => self.sockets.send_executed(o, parent).await, - Err(_) => {} - }, - // ValkyrieValue::DataFrame(_) => { - // todo!() - // } + Expr::Real(v) => { self.sockets.send_executed(v.to_string(), parent).await } + Expr::Sym(v) => { self.sockets.send_executed(v.to_string(), parent).await } + Expr::Str(v) => { self.sockets.send_executed(v.to_string(), parent).await } + Expr::List(v) => { self.sockets.send_executed(v.to_string(), parent).await } } } } diff --git a/projects/cas3-repl/src/lib.rs b/projects/cas3-repl/src/lib.rs index e69de29..18378c5 100644 --- a/projects/cas3-repl/src/lib.rs +++ b/projects/cas3-repl/src/lib.rs @@ -0,0 +1,97 @@ +use std::borrow::Cow; +use std::borrow::Cow::{Borrowed, Owned}; +use rustyline::{Completer, Helper, Hinter, Validator}; +use rustyline::error::ReadlineError; +use rustyline::highlight::{Highlighter, MatchingBracketHighlighter}; +use rustyline::validate::MatchingBracketValidator; +use cas3_core::{Cas3VM, evaluate, Expr, expr_parser}; + +#[derive(Helper, Completer, Hinter, Validator)] +pub struct ReplHelper { + pub highlighter: MatchingBracketHighlighter, + #[rustyline(Validator)] + pub validator: MatchingBracketValidator, + pub colored_prompt: String, +} + +impl Highlighter for ReplHelper { + fn highlight_prompt<'b, 's: 'b, 'p: 'b>( + &'s self, + prompt: &'p str, + default: bool, + ) -> Cow<'b, str> { + if default { + Borrowed(&self.colored_prompt) + } else { + Borrowed(prompt) + } + } + + fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { + Owned("\x1b[1m".to_owned() + hint + "\x1b[m") + } + + fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { + self.highlighter.highlight(line, pos) + } + + fn highlight_char(&self, line: &str, pos: usize) -> bool { + self.highlighter.highlight_char(line, pos) + } +} + +pub fn run( + mut rl: rustyline::Editor, + mut ctx: Cas3VM, +) -> rustyline::Result<()> { + let mut i = 1; + + loop { + let prompt = format!("(In {}) := ", i); + rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{prompt}\x1b[0m"); + + let line = rl.readline(&prompt); // read + match line { + Ok(l) => { + rl.add_history_entry(l.as_str()).unwrap(); // history + // saving every line (even if slow, just until its more stable) + rl.save_history("history.txt").unwrap(); + + let exs = expr_parser::expressions(&l); + + match exs { + Ok(exprs) => { + for expr in exprs { + let mut stack = Expr::List(vec![]); + let res = evaluate(&mut stack, &mut ctx, &expr); + let in_i = + expr_parser::Expr(format!("(setd (In {i}) {})", expr).as_str()) + .unwrap(); + evaluate(&mut stack, &mut ctx, &in_i); + let out_i = + expr_parser::Expr(format!("(set (Out {i}) {})", res).as_str()) + .unwrap(); + evaluate(&mut stack, &mut ctx, &out_i); + + println!("\x1B[1m(Out {i}) = {}\x1B[0m", res); + + i += 1; + } + } + + Err(err) => println!("Failed to parse: {}", err), + } + } + Err(ReadlineError::Interrupted) => { + continue; + } + Err(ReadlineError::Eof) => { + break; + } + Err(err) => { + println!("Error: {:?}", err); + } + } + } // loop + Ok(()) +} \ No newline at end of file diff --git a/projects/cas3-repl/src/main.rs b/projects/cas3-repl/src/main.rs index 5706cdf..530988c 100644 --- a/projects/cas3-repl/src/main.rs +++ b/projects/cas3-repl/src/main.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; use std::path::Path; use rustyline::config::Configurer; use rustyline::Editor; use rustyline::highlight::MatchingBracketHighlighter; use rustyline::validate::MatchingBracketValidator; -use cas3_core::{Cas3VM, ReplHelper, run, startup_attrs}; +use cas3::{ReplHelper, run}; +use cas3_core::{Cas3VM, startup_attrs}; fn main() -> rustyline::Result<()> { let h = ReplHelper { @@ -21,12 +21,13 @@ fn main() -> rustyline::Result<()> { } let mut ctx = Cas3VM::default(); + let here = Path::new(env!("CARGO_MANIFEST_DIR")); startup_attrs(&mut ctx); - ctx.run_file("lang/attrs.sexp")?; - ctx.run_file("lang/startup.sexp")?; - ctx.run_file("lang/calculus.sexp")?; + ctx.run_file(here.join("lang/attrs.sexp"))?; + ctx.run_file(here.join("lang/startup.sexp"))?; + ctx.run_file(here.join("lang/calculus.sexp"))?; // run_file(&mut ctx, Path::new("lang/systems.sexp"))?; run(rl, ctx)?; Ok(()) -} \ No newline at end of file +} From aa032875ca84ae0f9f4c8f72cc9e4bfada2f2099 Mon Sep 17 00:00:00 2001 From: Aster Date: Sat, 11 Nov 2023 19:20:03 +0000 Subject: [PATCH 6/8] fix error handlers --- projects/cas3-core/Cargo.toml | 1 + projects/cas3-core/src/errors/mod.rs | 17 +++++++++---- projects/cas3-core/src/lib.rs | 16 ++++++------- projects/cas3-core/src/tests.rs | 4 ++++ projects/cas3-jupyter/Cargo.toml | 2 +- projects/cas3-jupyter/src/executor/mod.rs | 24 ++++++++++--------- projects/cas3-jupyter/src/main.rs | 1 - projects/cas3-jupyter/src/protocol/display.rs | 1 - projects/cas3-jupyter/src/protocol/mod.rs | 6 ++--- projects/cas3-jupyter/tests/collection.vk | 1 - projects/cas3-jupyter/tests/literals.vk | 15 ------------ projects/cas3-jupyter/tests/main.rs | 23 ------------------ 12 files changed, 42 insertions(+), 69 deletions(-) delete mode 100644 projects/cas3-jupyter/tests/collection.vk delete mode 100644 projects/cas3-jupyter/tests/literals.vk diff --git a/projects/cas3-core/Cargo.toml b/projects/cas3-core/Cargo.toml index 4fb7383..66b9eae 100644 --- a/projects/cas3-core/Cargo.toml +++ b/projects/cas3-core/Cargo.toml @@ -3,6 +3,7 @@ name = "cas3-core" version = "0.1.0" edition = "2021" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/projects/cas3-core/src/errors/mod.rs b/projects/cas3-core/src/errors/mod.rs index 294c634..1c46979 100644 --- a/projects/cas3-core/src/errors/mod.rs +++ b/projects/cas3-core/src/errors/mod.rs @@ -13,6 +13,14 @@ pub enum Cas3ErrorKind { IoError(std::io::Error) } +impl Error for Cas3Error {} + +impl Display for Cas3Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Display::fmt(self.kind.as_ref(), f) + } +} + impl Display for Cas3ErrorKind { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { @@ -23,11 +31,10 @@ impl Display for Cas3ErrorKind { } } - -impl Display for Cas3Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.kind) +impl From for Cas3Error { + fn from(value: std::io::Error) -> Self { + Self { kind: Box::new(Cas3ErrorKind::IoError(value)) } } } -impl Error for Cas3Error {} \ No newline at end of file + diff --git a/projects/cas3-core/src/lib.rs b/projects/cas3-core/src/lib.rs index 9105701..7372403 100644 --- a/projects/cas3-core/src/lib.rs +++ b/projects/cas3-core/src/lib.rs @@ -1,6 +1,8 @@ // extern crate cairo; extern crate peg; + +pub use crate::errors::{Cas3Error, Cas3ErrorKind, Result}; use std::{ ops::{Add, Mul}, }; @@ -52,10 +54,6 @@ peg::parser! { } } -fn parse(s: &str) -> Expr { - expr_parser::Expr(s).unwrap() -} - #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum Expr { Int(num_bigint::BigInt), @@ -1461,7 +1459,7 @@ pub fn startup_attrs(ctx: &mut Cas3VM) { } impl Cas3VM { - pub fn run_file>(&mut self, filepath: P) -> std::io::Result { + pub fn run_file>(&mut self, filepath: P) -> Result { let filepath = filepath.as_ref(); // let file = File::open(filepath)?; // let reader = BufReader::new(file); @@ -1469,8 +1467,12 @@ impl Cas3VM { // i dont love this because it's ambigious whether or not something failed in reading the file or sth // or if the last expr in the file was a setd or something that returns a Null println!("Running file: {}", filepath.display()); + self.run_script(file_contents) + } + + pub fn run_script>(&mut self, file_contents: S) -> Result { let mut res = sym("Null"); - let exprs = expr_parser::expressions(&file_contents).unwrap(); + let exprs = expr_parser::expressions(file_contents.as_ref()).unwrap(); // for line in reader.lines() { for expr in exprs { // match line { @@ -1496,8 +1498,6 @@ impl Cas3VM { } - - pub fn evalparse(s: &str) -> Expr { let ex = expr_parser::Expr(s); match ex { diff --git a/projects/cas3-core/src/tests.rs b/projects/cas3-core/src/tests.rs index 8170a3c..a15b497 100644 --- a/projects/cas3-core/src/tests.rs +++ b/projects/cas3-core/src/tests.rs @@ -1,5 +1,9 @@ use super::*; +fn parse(s: &str) -> Expr { + expr_parser::Expr(s).unwrap() +} + #[test] fn test_parser() { assert_eq!(parse("(f (* *hi* *) x)"), parse("(f x)")); diff --git a/projects/cas3-jupyter/Cargo.toml b/projects/cas3-jupyter/Cargo.toml index aa5b08f..c6105da 100644 --- a/projects/cas3-jupyter/Cargo.toml +++ b/projects/cas3-jupyter/Cargo.toml @@ -2,7 +2,7 @@ name = "cas3-jupyter" version = "0.0.0" authors = ["Aster <192607617@qq.com>"] -description = "Jupyter Kernel for Valkyrie Language" +description = "Jupyter Kernel for cas3" repository = "https://github.com/nyar-vm/valkyrie-jupyter" documentation = "https://docs.rs/jupyter-valkyrie" readme = "readme.md" diff --git a/projects/cas3-jupyter/src/executor/mod.rs b/projects/cas3-jupyter/src/executor/mod.rs index 3c90837..321c735 100644 --- a/projects/cas3-jupyter/src/executor/mod.rs +++ b/projects/cas3-jupyter/src/executor/mod.rs @@ -1,7 +1,7 @@ use crate::{config::Cas3Config}; -use jupyter::{to_value, value_type::HtmlText, ExecutionRequest, JupyterError, JupyterKernelSockets, JupyterMessage}; +use jupyter::{ ExecutionRequest, JupyterKernelSockets, JupyterMessage}; use cas3_core::{Cas3VM, Expr}; - +use cas3_core::Result; pub struct CasExecutor { pub(crate) vm: Cas3VM, pub(crate) sockets: JupyterKernelSockets, @@ -15,14 +15,16 @@ impl Default for CasExecutor { } impl CasExecutor { - pub(crate) async fn repl_parse_and_run(&mut self, code: &ExecutionRequest) -> Result<(), ValkyrieError> { - let file = self.vm.load_snippet(&code.code, &format!("Cell{}", code.execution_count)); - for task in self.vm.execute_script(file).await { - match task { - Ok(v) => self.send_value(v, &code.header).await, - Err(e) => self.sockets.send_executed(JupyterError::custom(format!("Error: {}", e)), &code.header).await, - } - } + pub(crate) async fn repl_parse_and_run(&mut self, code: &ExecutionRequest) -> Result<()> { + // &format!("Cell{}", code.execution_count) + let file = self.vm.run_script(&code.code)?; + self.send_value(file, &code.header).await; + // for task in self.vm.execute_script(file).await { + // match task { + // Ok(v) => self.send_value(v, &code.header).await, + // Err(e) => self.sockets.send_executed(JupyterError::custom(format!("Error: {}", e)), &code.header).await, + // } + // } Ok(()) } @@ -34,7 +36,7 @@ impl CasExecutor { Expr::Real(v) => { self.sockets.send_executed(v.to_string(), parent).await } Expr::Sym(v) => { self.sockets.send_executed(v.to_string(), parent).await } Expr::Str(v) => { self.sockets.send_executed(v.to_string(), parent).await } - Expr::List(v) => { self.sockets.send_executed(v.to_string(), parent).await } + Expr::List(v) => { self.sockets.send_executed(format!("{v:#?}"), parent).await } } } } diff --git a/projects/cas3-jupyter/src/main.rs b/projects/cas3-jupyter/src/main.rs index 9a5367c..ecd4666 100644 --- a/projects/cas3-jupyter/src/main.rs +++ b/projects/cas3-jupyter/src/main.rs @@ -18,7 +18,6 @@ mod config; mod executor; mod protocol; -pub use crate::protocol::display::{DisplayKeywords, DisplayNumber, DisplayText}; /// #[derive(Debug, Parser)] diff --git a/projects/cas3-jupyter/src/protocol/display.rs b/projects/cas3-jupyter/src/protocol/display.rs index 4563e55..e69de29 100644 --- a/projects/cas3-jupyter/src/protocol/display.rs +++ b/projects/cas3-jupyter/src/protocol/display.rs @@ -1 +0,0 @@ -use super::*; diff --git a/projects/cas3-jupyter/src/protocol/mod.rs b/projects/cas3-jupyter/src/protocol/mod.rs index 846b791..5f5c457 100644 --- a/projects/cas3-jupyter/src/protocol/mod.rs +++ b/projects/cas3-jupyter/src/protocol/mod.rs @@ -1,7 +1,7 @@ use crate::executor::CasExecutor; use jupyter::{ - value_type::{JupyterContext, JupyterTheme}, - Executed, ExecutionReply, ExecutionRequest, JupyterConnection, JupyterError, JupyterKernelProtocol, LanguageInfo, Value, + + ExecutionReply, ExecutionRequest, JupyterConnection, JupyterError, JupyterKernelProtocol, LanguageInfo, }; use jupyter_derive::include_png32; @@ -10,7 +10,7 @@ pub mod display; impl JupyterKernelProtocol for CasExecutor { fn language_info(&self) -> LanguageInfo { let mut info = - LanguageInfo::new("valkyrie", "Valkyrie").with_syntax("scala", "scala").with_version(env!("CARGO_PKG_VERSION")); + LanguageInfo::new("cas3", "Cas3").with_syntax("schema", "schema").with_version(env!("CARGO_PKG_VERSION")); info.png_32 = include_png32!(); info.png_64 = include_png32!(); return info; diff --git a/projects/cas3-jupyter/tests/collection.vk b/projects/cas3-jupyter/tests/collection.vk deleted file mode 100644 index 4b1004b..0000000 --- a/projects/cas3-jupyter/tests/collection.vk +++ /dev/null @@ -1 +0,0 @@ -(1, 2, a: 3);; diff --git a/projects/cas3-jupyter/tests/literals.vk b/projects/cas3-jupyter/tests/literals.vk deleted file mode 100644 index e18909b..0000000 --- a/projects/cas3-jupyter/tests/literals.vk +++ /dev/null @@ -1,15 +0,0 @@ -true -false - -nil -null - -0 -1 -2 -3 - -"string" -"string formatter { 0 }" - -r"raw string" diff --git a/projects/cas3-jupyter/tests/main.rs b/projects/cas3-jupyter/tests/main.rs index 99f81dc..cf5bed2 100644 --- a/projects/cas3-jupyter/tests/main.rs +++ b/projects/cas3-jupyter/tests/main.rs @@ -2,26 +2,3 @@ fn ready() { println!("it works!") } - -use std::path::Path; -use valkyrie_interpreter::ValkyrieVM; - -#[tokio::test] -async fn tests() { - debug_wrong("tests/literals.vk").await.unwrap(); - debug_wrong("tests/collection.vk").await.unwrap(); -} - -async fn debug_wrong>(file: P) -> std::io::Result<()> { - let mut vm = ValkyrieVM::default(); - let file = vm.load_file(file.as_ref().canonicalize()?)?; - for i in vm.execute_script(file).await { - match i { - Ok(o) => { - println!("{:#?}", o); - } - Err(e) => e.as_report().eprint(vm.as_ref())?, - } - } - Ok(()) -} From d0fb3438120fb4fd3cbdd6b8b50ed1b4b6681699 Mon Sep 17 00:00:00 2001 From: Aster Date: Sun, 12 Nov 2023 19:30:16 +0000 Subject: [PATCH 7/8] add the playground --- .gitignore | 5 + Cargo.lock | 28 ++--- projects/cas3-jupyter/Cargo.toml | 6 +- projects/cas3-jupyter/readme.md | 8 ++ projects/playground/install.ipynb | 48 +++++++ projects/playground/main.ipynb | 201 ++++++++++++++++++++++++++++++ projects/playground/package.json | 6 + projects/playground/readme.md | 10 ++ 8 files changed, 295 insertions(+), 17 deletions(-) create mode 100644 projects/playground/install.ipynb create mode 100644 projects/playground/main.ipynb create mode 100644 projects/playground/package.json create mode 100644 projects/playground/readme.md diff --git a/.gitignore b/.gitignore index a0cb275..152d749 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,9 @@ ## Rust target/ + + +## Cache +.ipynb_checkpoints/ +.virtual_documents/ history.txt diff --git a/Cargo.lock b/Cargo.lock index a1f9a29..c6fa081 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,20 +207,6 @@ dependencies = [ "peg", ] -[[package]] -name = "cas3-jupyter" -version = "0.0.0" -dependencies = [ - "async-trait", - "cas3-core", - "clap", - "jupyter", - "jupyter-derive", - "tokio", - "tracing-subscriber", - "url", -] - [[package]] name = "cc" version = "1.0.83" @@ -801,6 +787,20 @@ dependencies = [ "zeromq", ] +[[package]] +name = "jupyter-cas3" +version = "0.0.0" +dependencies = [ + "async-trait", + "cas3-core", + "clap", + "jupyter", + "jupyter-derive", + "tokio", + "tracing-subscriber", + "url", +] + [[package]] name = "jupyter-derive" version = "0.0.2" diff --git a/projects/cas3-jupyter/Cargo.toml b/projects/cas3-jupyter/Cargo.toml index c6105da..e3e39d9 100644 --- a/projects/cas3-jupyter/Cargo.toml +++ b/projects/cas3-jupyter/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "cas3-jupyter" +name = "jupyter-cas3" version = "0.0.0" authors = ["Aster <192607617@qq.com>"] description = "Jupyter Kernel for cas3" -repository = "https://github.com/nyar-vm/valkyrie-jupyter" -documentation = "https://docs.rs/jupyter-valkyrie" +repository = "https://github.com/anandijain/cas3.rs" +documentation = "https://docs.rs/cas3-jupyter" readme = "readme.md" license = "MPL-2.0" edition = "2021" diff --git a/projects/cas3-jupyter/readme.md b/projects/cas3-jupyter/readme.md index db86903..f112650 100644 --- a/projects/cas3-jupyter/readme.md +++ b/projects/cas3-jupyter/readme.md @@ -1,2 +1,10 @@ Title ===== + + + +### Install + +```shell +cargo install --path . +``` \ No newline at end of file diff --git a/projects/playground/install.ipynb b/projects/playground/install.ipynb new file mode 100644 index 0000000..42d923f --- /dev/null +++ b/projects/playground/install.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "python" + }, + "is_executing": true + }, + "outputs": [], + "source": [ + "!wget \"https:/github\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/projects/playground/main.ipynb b/projects/playground/main.ipynb new file mode 100644 index 0000000..07aecbf --- /dev/null +++ b/projects/playground/main.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4cd56fd8-db0b-4218-ac27-ef0e26f93ac9", + "metadata": {}, + "source": [ + "# Introduce" + ] + }, + { + "cell_type": "markdown", + "id": "8eaadd94-e9eb-40a2-a377-b2051dda88d4", + "metadata": { + "tags": [] + }, + "source": [ + "## Online Playground\n", + "\n", + "### Binder\n", + "\n", + "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/nyar-vm/valkyrie-jupyter/dev?labpath=playground%2FMain.ipynb)" + ] + }, + { + "cell_type": "markdown", + "id": "9460ba1c-37b6-46ba-9f43-1205ac8c1e9e", + "metadata": {}, + "source": [ + "## Install\n", + "\n", + "\n", + "For rust user\n", + "\n", + "```sh\n", + "cargo install valkyrie-jupyter\n", + "valkyrie-jupyter install\n", + "```\n", + "\n", + "For manally download:\n", + "\n", + "\n", + "```\n", + "\n", + "```\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "e5114ecc-6439-4fe5-90b2-e456709bbaa5", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "tags": [] + }, + "source": [ + "## Basic Tutorial\n", + "\n", + "### [Literals](./basic/literals.ipynb)\n", + "\n", + "bool, integer, decimal, string literal, json, html, ...\n", + "\n", + "### [Collections](./basic/literals.ipynb#Collections)\n", + "\n", + "Table, List, Dict, Maps, Sets, Bits, Bytes, ...\n", + "\n", + "\n", + "### [Let Binding](./basic/let-binding.ipynb)\n", + "\n", + "How to define variables and output\n", + "\n", + "### [Extression](./basic/expressions.ipynb)\n", + "\n", + "How to call functions and subroutines\n", + "\n", + "\n", + "### [Define Function](./basic/function.ipynb)\n", + "\n", + "How to define a function\n", + "\n", + "\n", + "### 【TODO】[Structure & Class](./basic/class.ipynb)\n", + "\n", + "How to define a class\n", + "\n", + "### 【TODO】[Interface & Trait](./basic/trait.ipynb)\n", + "\n", + "How to define a trait\n", + "\n", + "### 【TODO】[Union & Variant](./basic/trait.ipynb)\n", + "\n", + "How to define a union\n", + "\n", + "### 【TODO】[Flags](./basic/trait.ipynb)\n", + "\n", + "How to define a flag\n", + "\n", + "\n", + "### 【TODO】[Modules](./basic/modules.ipynb)\n", + "\n", + "\n", + "### 【TODO】[Packages](./basic/packages.ipynb)\n", + "\n", + "\n", + "\n", + "\n", + "### [Control Flow](./basic/control-flow.ipynb)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "6c2d226b-e773-4937-8ade-1710aa395630", + "metadata": {}, + "source": [ + "## Advanced Tutorial" + ] + }, + { + "cell_type": "markdown", + "id": "80e7f8d6-ccfc-43b8-ab57-7c6e13c872c7", + "metadata": {}, + "source": [ + "### 【TODO】[Work with Iterator](./advance/iterator.ipynb)\n", + "\n", + "\n", + "\n", + "### 【TODO】[Work with Generator](./advance/generator.ipynb)\n", + "\n", + "\n", + "### 【TODO】[Work with Coroutine](./advance/coroutine.ipynb)\n", + "\n", + "\n", + "### 【TODO】[Work with Observer](./advance/observer.ipynb)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76b9e9b5-fa38-4026-bfcc-1970e3a48afe", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcbca8fa-ba08-44ca-b3a1-66bad374efbb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e50bd50c-8879-4873-a62b-8003d223cd8a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c2476439-4e6b-43bc-87c5-c0a2aa7017c1", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e8fccb1-6a36-48de-852d-649dc3cd7311", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Valkyrie", + "language": "valkyrie", + "name": "valkyrie" + }, + "language_info": { + "codemirror_mode": "rust", + "file_extension": "*.rs", + "mimetype": "scala", + "name": "Valkyrie", + "nbconvert_exporter": "rust", + "pygment_lexer": "scala", + "version": "0.0.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/projects/playground/package.json b/projects/playground/package.json new file mode 100644 index 0000000..1170b3f --- /dev/null +++ b/projects/playground/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "scripts": { + "w": "jupyter-lab" + } +} diff --git a/projects/playground/readme.md b/projects/playground/readme.md new file mode 100644 index 0000000..7800406 --- /dev/null +++ b/projects/playground/readme.md @@ -0,0 +1,10 @@ + +## Emoji Comment + + + +- Windows: + +```shell +cargo build; jupyter-lab; +``` \ No newline at end of file From 2aa7f0c1a91ab555e9ae9b2aed2eb9ca863d7d34 Mon Sep 17 00:00:00 2001 From: Aster Date: Tue, 14 Nov 2023 09:56:08 +0000 Subject: [PATCH 8/8] run examples in jupyter lab --- .gitignore | 1 + projects/cas3-core/readme.md | 0 projects/cas3-jupyter/readme.md | 9 + projects/playground/main.ipynb | 416 ++++++++++++++++++++++++++------ 4 files changed, 348 insertions(+), 78 deletions(-) create mode 100644 projects/cas3-core/readme.md diff --git a/.gitignore b/.gitignore index 152d749..69c070b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ target/ ## Cache .ipynb_checkpoints/ .virtual_documents/ +Untitled.ipynb history.txt diff --git a/projects/cas3-core/readme.md b/projects/cas3-core/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/projects/cas3-jupyter/readme.md b/projects/cas3-jupyter/readme.md index f112650..23baef1 100644 --- a/projects/cas3-jupyter/readme.md +++ b/projects/cas3-jupyter/readme.md @@ -7,4 +7,13 @@ Title ```shell cargo install --path . +``` + + +### Playground + + +```shell +cd projects/playground +jupyter-lab ``` \ No newline at end of file diff --git a/projects/playground/main.ipynb b/projects/playground/main.ipynb index 07aecbf..2681f2a 100644 --- a/projects/playground/main.ipynb +++ b/projects/playground/main.ipynb @@ -19,7 +19,7 @@ "\n", "### Binder\n", "\n", - "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/nyar-vm/valkyrie-jupyter/dev?labpath=playground%2FMain.ipynb)" + "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cas3/cas3/dev?labpath=playground%2Fmain.ipynb)" ] }, { @@ -33,8 +33,8 @@ "For rust user\n", "\n", "```sh\n", - "cargo install valkyrie-jupyter\n", - "valkyrie-jupyter install\n", + "cargo install jupyter-cas3\n", + "jupyter-cas install\n", "```\n", "\n", "For manally download:\n", @@ -46,71 +46,341 @@ "\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d4ef593-5119-40c5-8177-6f705b212607", + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "id": "e5114ecc-6439-4fe5-90b2-e456709bbaa5", "metadata": { - "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "## Basic Tutorial\n", - "\n", - "### [Literals](./basic/literals.ipynb)\n", - "\n", - "bool, integer, decimal, string literal, json, html, ...\n", - "\n", - "### [Collections](./basic/literals.ipynb#Collections)\n", - "\n", - "Table, List, Dict, Maps, Sets, Bits, Bytes, ...\n", - "\n", - "\n", - "### [Let Binding](./basic/let-binding.ipynb)\n", - "\n", - "How to define variables and output\n", - "\n", - "### [Extression](./basic/expressions.ipynb)\n", - "\n", - "How to call functions and subroutines\n", - "\n", - "\n", - "### [Define Function](./basic/function.ipynb)\n", - "\n", - "How to define a function\n", - "\n", - "\n", - "### 【TODO】[Structure & Class](./basic/class.ipynb)\n", - "\n", - "How to define a class\n", - "\n", - "### 【TODO】[Interface & Trait](./basic/trait.ipynb)\n", - "\n", - "How to define a trait\n", - "\n", - "### 【TODO】[Union & Variant](./basic/trait.ipynb)\n", - "\n", - "How to define a union\n", - "\n", - "### 【TODO】[Flags](./basic/trait.ipynb)\n", - "\n", - "How to define a flag\n", - "\n", - "\n", - "### 【TODO】[Modules](./basic/modules.ipynb)\n", - "\n", - "\n", - "### 【TODO】[Packages](./basic/packages.ipynb)\n", - "\n", - "\n", - "\n", - "\n", - "### [Control Flow](./basic/control-flow.ipynb)\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "## Basic Tutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cde2f06a-5afb-4d96-a805-f9770954b862", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[\n", + " Sym(\n", + " \"list\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"rule\",\n", + " ),\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " Sym(\n", + " \"s\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"x\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"y\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"z\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"x\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"z\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"y\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"z\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"rule\",\n", + " ),\n", + " List(\n", + " [\n", + " List(\n", + " [\n", + " Sym(\n", + " \"k\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"x\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"y\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"pattern\",\n", + " ),\n", + " Sym(\n", + " \"x\",\n", + " ),\n", + " List(\n", + " [\n", + " Sym(\n", + " \"blank\",\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + " ],\n", + " ),\n", + "]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(* Computing with Combinators *)\n", + "(* First we define the sk rules *)\n", + "(set sk_rules (list (rule (((s (pattern x (blank))) (pattern y (blank))) (pattern z (blank))) ((x z) (y z))) (rule ((k (pattern x (blank))) (pattern y (blank))) x)))" ] }, { @@ -126,17 +396,7 @@ "id": "80e7f8d6-ccfc-43b8-ab57-7c6e13c872c7", "metadata": {}, "source": [ - "### 【TODO】[Work with Iterator](./advance/iterator.ipynb)\n", - "\n", - "\n", - "\n", - "### 【TODO】[Work with Generator](./advance/generator.ipynb)\n", - "\n", - "\n", - "### 【TODO】[Work with Coroutine](./advance/coroutine.ipynb)\n", - "\n", - "\n", - "### 【TODO】[Work with Observer](./advance/observer.ipynb)\n" + "\n" ] }, { @@ -182,17 +442,17 @@ ], "metadata": { "kernelspec": { - "display_name": "Valkyrie", - "language": "valkyrie", - "name": "valkyrie" + "display_name": "Cas3", + "language": "cas3", + "name": "cas3" }, "language_info": { "codemirror_mode": "rust", "file_extension": "*.rs", - "mimetype": "scala", - "name": "Valkyrie", + "mimetype": "schema", + "name": "Cas3", "nbconvert_exporter": "rust", - "pygment_lexer": "scala", + "pygment_lexer": "schema", "version": "0.0.0" } },