~fd/cane-lang

5179dfab83dd027263e582c60b1788248cde44de — Ersei Saggi 10 months ago 8cb936e
Switch from rug to malachite because WASM
11 files changed, 176 insertions(+), 66 deletions(-)

M Cargo.toml
A cane-lang/Cargo.toml
R src/main.rs => cane-lang/src/cli.rs
R src/interpreter.rs => cane-lang/src/lib.rs
R src/stdtypes.rs => cane-lang/src/stdtypes.rs
A cane-wasm/Cargo.toml
A cane-wasm/index.html
A cane-wasm/src/lib.rs
A demos/duplicate.cn
M demos/hello.cn
M shell.nix
M Cargo.toml => Cargo.toml +8 -13
@@ 1,15 1,10 @@
[package]
name = "cane-lang"
version = "0.1.0"
edition = "2021"
authors = ["Ersei Saggi <me@ersei.net>"]
description = "A strange programming language"
license = "Apache-2.0"
repository = "https://git.sr.ht/~fd/cane-lang"
[workspace]

[[bin]]
name = "cane"
path = "src/main.rs"
members = [
    "cane-lang",
	"cane-wasm",
]

[dependencies]
rug = "1.19"
[profile.release]
lto = true
strip = true

A cane-lang/Cargo.toml => cane-lang/Cargo.toml +18 -0
@@ 0,0 1,18 @@
[package]
name = "cane"
version = "0.1.0"
edition = "2021"
authors = ["Ersei Saggi <me@ersei.net>"]
description = "A strange programming language"
license = "Apache-2.0"
repository = "https://git.sr.ht/~fd/cane-lang"

[lib]
path = "src/lib.rs"

[[bin]]
name = "cane"
path = "src/cli.rs"

[dependencies]
malachite-q = "0.3"

R src/main.rs => cane-lang/src/cli.rs +4 -7
@@ 1,9 1,6 @@
mod interpreter;
mod stdtypes;
use cane::stdtypes::{Data,Types};

use stdtypes::Data;

use crate::interpreter::Interpreter;
use cane::Interpreter;
use std::collections::HashMap;
use std::{env, fs::File, io::BufReader, io::Error, io::ErrorKind};



@@ 20,9 17,9 @@ fn main() -> std::io::Result<Data> {
    let reader = BufReader::new(f);
    let mut stdout = std::io::stdout();
    let mut variables = HashMap::new();
    let mut args_data = Data::new(stdtypes::Types::LIST);
    let mut args_data = Data::new(Types::LIST);
    for arg in args {
        let mut data = Data::new(stdtypes::Types::STRING);
        let mut data = Data::new(Types::STRING);
        data.set_string(arg);
        args_data.get_list().push(data);
    }

R src/interpreter.rs => cane-lang/src/lib.rs +7 -5
@@ 1,9 1,12 @@
use crate::stdtypes::{Data, Number, Types};
use rug::Rational;
pub mod stdtypes;

use malachite_q::Rational;
use std::collections::HashMap;
use std::io::{self, BufReader, Cursor, Error, ErrorKind, Read, Seek, SeekFrom, Write};
use std::str::from_utf8;
use std::str::FromStr;
use std::u8;
use stdtypes::{Data, Number, Types};

#[derive(PartialEq, Eq, Debug)]
enum State {


@@ 566,9 569,8 @@ where
                                        .insert(key.unwrap().to_string(), var.unwrap());
                                }
                                _ => {
                                    match Rational::from_str_radix(
                                    match Rational::from_str(
                                        self.call_stack.last_mut().unwrap().get_token().as_str(),
                                        10,
                                    ) {
                                        Ok(val) => {
                                            let mut data = Data::new(Types::NUMBER);


@@ 580,7 582,7 @@ where
                                                .get_list()
                                                .push(data);
                                        }
                                        Err(_) => {
                                        Err(..) => {
                                            reset = false;
                                        }
                                    }

R src/stdtypes.rs => cane-lang/src/stdtypes.rs +41 -40
@@ 1,9 1,10 @@
use rug::Rational;
use malachite_q::Rational;
use std::cmp::Ordering;
use std::collections::linked_list::{Iter, IterMut};
use std::collections::LinkedList;
use std::fmt;
use std::process::{ExitCode, Termination};
use std::str::FromStr;

/// Represents a doubly-linked list
#[derive(Clone, Debug, PartialOrd, PartialEq)]


@@ 65,7 66,7 @@ fn string_to_list(str: &String) -> List {
///
/// * `list` - A list object
fn list_to_number(list: &List) -> Number {
    Number(Rational::from((list.0.len(), 1)))
    Number(Rational::from_unsigneds(list.0.len(), 1))
}

/// Converts a list to a string. Merges the list recursively into a string.


@@ 92,12 93,12 @@ fn number_to_string(num: &Number) -> String {
///
/// * `str` - A string representation of an improper fraction.
fn string_to_number(str: &String) -> Number {
    return Number(Rational::from_str_radix(str, 10).unwrap());
    return Number(Rational::from_str(str).unwrap());
}

impl fmt::Display for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0.to_string_radix(10))
        write!(f, "{}", self.0.to_string())
    }
}



@@ 194,19 195,19 @@ impl Number {
        Self { 0: number }
    }
    pub fn is_integer(&self) -> bool {
        self.0.denom() == &1
        self.0.denominator_ref() == &1
    }
    pub fn is_positive(&self) -> bool {
        self.0.numer() > &0
        self.0.numerator_ref() > &0
    }
    pub fn is_zero(&self) -> bool {
        self.0.numer() == &0
        self.0.numerator_ref() == &0
    }
    pub fn is_not_negative(&self) -> bool {
        self.0.numer() >= &0
        self.0.numerator_ref() >= &0
    }
    pub fn decrement(&mut self) {
        self.0 -= 1;
        self.0 -= Rational::from_signeds(1, 1);
    }
}



@@ 279,7 280,7 @@ impl Data {
        Self {
            kind,
            val_string: "".to_string(),
            val_number: Number(Rational::new()),
            val_number: Number(Rational::from_signeds(0, 1)),
            val_list: List(LinkedList::new()),
        }
    }


@@ 399,7 400,7 @@ impl Data {
    pub fn erase(&mut self) {
        self.val_string = "".to_string();
        self.val_list.0 = LinkedList::new();
        self.val_number.0 = Rational::from((0, 1));
        self.val_number.0 = Rational::from_signeds(0, 1);
    }

    pub fn is_sorted_asc(&self) -> bool {


@@ 525,23 526,23 @@ impl Data {
#[cfg(test)]
mod tests {
    use crate::stdtypes::*;
    use rug::Rational;
    use malachite_q::Rational;

    #[test]
    fn test_add_flat_nums() {
        let mut list1 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.val_number.0 = Rational::from((4, 3));
        item1.val_number.0 = Rational::from_signeds(4, 3);

        let mut item2 = Data::new(Types::NUMBER);
        item2.val_number.0 = Rational::from((1, 2));
        item2.val_number.0 = Rational::from_signeds(1, 2);

        let mut item3 = Data::new(Types::NUMBER);
        item3.val_number.0 = Rational::from((1, 1));
        item3.val_number.0 = Rational::from_signeds(1, 1);

        let mut item4 = Data::new(Types::NUMBER);
        item4.val_number.0 = Rational::from((18, 1));
        item4.val_number.0 = Rational::from_signeds(18, 1);

        list1.val_list.0.push_back(item1);
        list1.val_list.0.push_back(item2);


@@ 550,7 551,7 @@ mod tests {

        list1.add();

        assert_eq!(list1.val_number.0, Rational::from((125, 6)));
        assert_eq!(list1.val_number.0, Rational::from_signeds(125, 6));
    }

    #[test]


@@ 648,11 649,11 @@ mod tests {
        let mut sum3 = Data::new(Types::NUMBER);
        let mut sum4 = Data::new(Types::NUMBER);
        let mut sum5 = Data::new(Types::NUMBER);
        sum1.val_number = Number(Rational::from((1, 1)));
        sum2.val_number = Number(Rational::from((2, 1)));
        sum3.val_number = Number(Rational::from((3, 1)));
        sum4.val_number = Number(Rational::from((4, 1)));
        sum5.val_number = Number(Rational::from((5, 1)));
        sum1.val_number = Number(Rational::from_signeds(1, 1));
        sum2.val_number = Number(Rational::from_signeds(2, 1));
        sum3.val_number = Number(Rational::from_signeds(3, 1));
        sum4.val_number = Number(Rational::from_signeds(4, 1));
        sum5.val_number = Number(Rational::from_signeds(5, 1));
        list3.val_list.0.push_back(sum1);
        list3.val_list.0.push_back(sum2);
        list3.val_list.0.push_back(sum3);


@@ 686,18 687,18 @@ mod tests {
        let mut list1 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.val_number.0 = Rational::from((4, 3));
        item1.val_number.0 = Rational::from_signeds(4, 3);

        let mut item2 = Data::new(Types::NUMBER);
        item2.val_number.0 = Rational::from((1, 2));
        item2.val_number.0 = Rational::from_signeds(1, 2);

        let mut list2 = Data::new(Types::LIST);

        let mut item3 = Data::new(Types::NUMBER);
        item3.val_number.0 = Rational::from((4, 3));
        item3.val_number.0 = Rational::from_signeds(4, 3);

        let mut item4 = Data::new(Types::NUMBER);
        item4.val_number.0 = Rational::from((1, 2));
        item4.val_number.0 = Rational::from_signeds(1, 2);

        list1.val_list.0.push_back(item1);
        list1.val_list.0.push_back(item2);


@@ 716,7 717,7 @@ mod tests {
        let mut list1 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.val_number.0 = Rational::from((4, 1));
        item1.val_number.0 = Rational::from_signeds(4, 1);

        let mut list2 = Data::new(Types::LIST);



@@ 736,16 737,16 @@ mod tests {
        let mut list1 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.val_number.0 = Rational::from((1, 1));
        item1.val_number.0 = Rational::from_signeds(1, 1);

        let mut item2 = Data::new(Types::NUMBER);
        item2.val_number.0 = Rational::from((2, 1));
        item2.val_number.0 = Rational::from_signeds(2, 1);

        let mut item3 = Data::new(Types::NUMBER);
        item3.val_number.0 = Rational::from((7, 3));
        item3.val_number.0 = Rational::from_signeds(7, 3);

        let mut item4 = Data::new(Types::NUMBER);
        item4.val_number.0 = Rational::from((15, 2));
        item4.val_number.0 = Rational::from_signeds(15, 2);

        list1.val_list.0.push_back(item1);
        list1.val_list.0.push_back(item2);


@@ 756,7 757,7 @@ mod tests {
        assert!(list1.is_sorted_asc_eq());

        let mut item5 = Data::new(Types::NUMBER);
        item5.val_number.0 = Rational::from((15, 2));
        item5.val_number.0 = Rational::from_signeds(15, 2);
        list1.val_list.0.push_back(item5);

        assert!(!list1.is_sorted_asc());


@@ 768,16 769,16 @@ mod tests {
        let mut list1 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.val_number.0 = Rational::from((15, 2));
        item1.val_number.0 = Rational::from_signeds(15, 2);

        let mut item2 = Data::new(Types::NUMBER);
        item2.val_number.0 = Rational::from((7, 3));
        item2.val_number.0 = Rational::from_signeds(7, 3);

        let mut item3 = Data::new(Types::NUMBER);
        item3.val_number.0 = Rational::from((2, 1));
        item3.val_number.0 = Rational::from_signeds(2, 1);

        let mut item4 = Data::new(Types::NUMBER);
        item4.val_number.0 = Rational::from((1, 1));
        item4.val_number.0 = Rational::from_signeds(1, 1);

        list1.val_list.0.push_back(item1);
        list1.val_list.0.push_back(item2);


@@ 788,7 789,7 @@ mod tests {
        assert!(list1.is_sorted_desc_eq());

        let mut item5 = Data::new(Types::NUMBER);
        item5.val_number.0 = Rational::from((1, 1));
        item5.val_number.0 = Rational::from_signeds(1, 1);
        list1.val_list.0.push_back(item5);

        assert!(!list1.is_sorted_desc());


@@ 803,11 804,11 @@ mod tests {
        let mut list3 = Data::new(Types::LIST);

        let mut item1 = Data::new(Types::NUMBER);
        item1.set_number(Number::new(Rational::from((1, 1))));
        item1.set_number(Number::new(Rational::from_signeds(1, 1)));
        let mut item2 = Data::new(Types::NUMBER);
        item2.set_number(Number::new(Rational::from((2, 1))));
        item2.set_number(Number::new(Rational::from_signeds(2, 1)));
        let mut item3 = Data::new(Types::NUMBER);
        item3.set_number(Number::new(Rational::from((3, 1))));
        item3.set_number(Number::new(Rational::from_signeds(3, 1)));

        list1.val_list.0.push_back(item1);
        list2.val_list.0.push_back(item2);

A cane-wasm/Cargo.toml => cane-wasm/Cargo.toml +12 -0
@@ 0,0 1,12 @@
[package]
name = "cane_wasm"
version = "0.1.0"
edition = "2021"
authors = ["Ersei Saggi <me@ersei.net>"]
description = "A strange programming language"
license = "Apache-2.0"
repository = "https://git.sr.ht/~fd/cane-lang"

[dependencies]
cane = { path = "../cane-lang" }
wasm-bindgen = "0.2"

A cane-wasm/index.html => cane-wasm/index.html +15 -0
@@ 0,0 1,15 @@
<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>hello-world example</title>
  </head>
  <body>
    <script type="module">
      import init, { interpreter } from "./pkg/cane_lang.js";
      init().then(() => {
        interpreter("(`hello, world!' print)", "");
      });
    </script>
  </body>
</html>

A cane-wasm/src/lib.rs => cane-wasm/src/lib.rs +68 -0
@@ 0,0 1,68 @@
use wasm_bindgen::prelude::*;

use cane::stdtypes::{Data,Types};

use cane::Interpreter;
use std::collections::HashMap;
use std::io::BufReader;
use std::io::{Cursor, Write};

#[wasm_bindgen]
extern "C" {
    pub fn alert(s: &str);

    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

struct JSOut {}

impl JSOut {
    fn new() -> Self {
        Self {}
    }
}

impl Write for JSOut {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        log("writing data...");
        log(std::str::from_utf8(buf).unwrap());
        log("success!");
        Ok(buf.len())
    }
    fn flush(&mut self) -> std::io::Result<()> {
        log("flushing...");
        Ok(())
    }
}

#[wasm_bindgen]
pub fn interpreter(input: &str, args_str: &str) {
    let args: Vec<_> = args_str.split(" ").collect();
    let mut c = Cursor::new(Vec::new());
    let test_input = input.as_bytes();

    c.write_all(test_input).unwrap();
    let reader = BufReader::new(c);

    let mut stdout = JSOut::new();

    let mut variables = HashMap::new();
    let mut args_data = Data::new(Types::LIST);

    for arg in args {
        let mut data = Data::new(Types::STRING);
        data.set_string(arg.to_string());
        args_data.get_list().push(data);
    }

    let mut runner = Interpreter::new(reader, &mut stdout, &mut variables, args_data);

    log("here");

    match runner.execute() {
        Ok(..) => (),
        Err(text) => alert(&text.to_string()),
    }
    log("done");
}

A demos/duplicate.cn => demos/duplicate.cn +1 -0
@@ 0,0 1,1 @@
(1 10 duplicate add print)

M demos/hello.cn => demos/hello.cn +1 -0
@@ 1,3 1,4 @@
; Simple "Hello, world!" program ~

(`hello, ' `world\n' add print)
(`hello, world!' print)

M shell.nix => shell.nix +1 -1
@@ 1,5 1,5 @@
let
  pkgs = import (fetchTarball("channel:nixpkgs-unstable")) {};
in pkgs.mkShell {
  buildInputs = [ pkgs.cargo pkgs.rustc pkgs.m4 pkgs.rustfmt pkgs.rust-analyzer ];
  buildInputs = [ pkgs.rustfmt pkgs.rust-analyzer pkgs.wasm-pack pkgs.rustup pkgs.pkg-config pkgs.openssl ];
}