From 10ebab6b90644143c19547914a5995f1c8fb9713 Mon Sep 17 00:00:00 2001 From: Artemy Date: Thu, 4 Aug 2022 19:05:56 +0300 Subject: [PATCH] feat: input, sleep --- Cargo.lock | 14 ++-- Cargo.toml | 2 +- README.md | 29 ++++++++ ROADMAP.md | 12 ++++ doc/main.md | 140 ++++++++++++++++++++++++++++++++++++ test.json5 => example.json5 | 51 ++++++++----- src/interpreter.rs | 36 +++++++++- src/main.rs | 1 - 8 files changed, 256 insertions(+), 29 deletions(-) create mode 100644 README.md create mode 100644 ROADMAP.md create mode 100644 doc/main.md rename test.json5 => example.json5 (83%) diff --git a/Cargo.lock b/Cargo.lock index c7281e7..0c3adad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,13 +190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "onlang" +name = "on" version = "0.1.0" dependencies = [ "clap", @@ -206,6 +200,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "os_str_bytes" version = "6.2.0" diff --git a/Cargo.toml b/Cargo.toml index 1912b3b..c31388b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "onlang" +name = "on" version = "0.1.0" edition = "2021" diff --git a/README.md b/README.md new file mode 100644 index 0000000..cd0fa13 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +![onlang logo](static/logos/OnLang-transparent.png) + +# You may have questions + +ONLang - Object Notation Language (js`ON`) + +## 1. God, what the f\*\*\*\* is this + +ONLang is an experimental, esoteric programming language, that allows you to use **json** for **PROGRAMMING**. The interpreter currently supports only json5 format. + +## 2. What is it for + +For writing simple scripts. + +## 3. How run scripts + +1. Add the executable file to the path variable +2. `on example.json5` + +or + +1. Clone this repo +2. `cargo run --quiet --release -- example.json5` + +## 4. How to write on this + +[Documentation](doc/main.md) + +If you want to help create a pull request diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..95efd85 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,12 @@ +# TODO CONCEPTS + +1. Functions +2. imports +3. scopes of visibility +4. parallel tasks `{parallel:[..tasks]}` +5. types conversion +6. methods for arrays +7. writing objects to a variable +8. yaml support? + +and something else diff --git a/doc/main.md b/doc/main.md new file mode 100644 index 0000000..5dcef44 --- /dev/null +++ b/doc/main.md @@ -0,0 +1,140 @@ +# How to + +`All posibilities in example.json5` + +## How to print + +```json5 +[ + "Just string in array", + ["array", "of", "strings"], + { + print: ["Function"], + }, + { + println: ["Function"], + }, +] +``` + +## How to calclulate values + +works only with numbers (and variables with number type) + +```json5 +[ + { calc: [2, "*", 3] }, //only 3 arguments + { calc: [{ var: "some_variable" }, "-", 2] }, //{var:"some_var"} this is a way to get a variable +] +``` + +### Supported operators + +1. \+ +2. \- +3. \* +4. \/ +5. \% +6. \>\> +7. \<\< +8. \^ +9. \& +10. \| + +## How to compare values + +```json5 +[ + { comp: [true, "!=", false] }, //only 3 arguments + { + comp: [ + { + comp: [ + { comp: [{ calc: [1, "+", 1] }, ">", 3] }, + "==", + { var: "var_with_bool_value" }, + ], + }, + "&&", + { comp: [{ comp: [{ calc: [1, "+", 1] }, ">", 3] }, "==", true] }, + ], + }, //more complex comparisons: (( 1 + 1 > 3 ) == var_with_bool_value) && (( 1 + 1 > 3 ) == true) +] +``` + +### Supported operators for compare + +1. == +2. != +3. \> +4. \< +5. \>= +6. \<= +7. \&\& +8. \|\| + +## How to create a variable + +```json5 +[ + { + let: { + str: "A", + num: 2, + arr: ["Array", "in", "variable"], + }, + }, + + { + let: { + calculated: { calc: [{ var: "num" }, "*", 4] }, //result 8 + }, + }, +] +``` + +## How to assign variable + +```json5 +[ + { + assign: { + calculated: { calc: [{ var: "calculated" }, "+", 1] }, // calculated = calculated + 1 + }, + }, +] +``` + +## Loops + +```json5 +[ + { + loop: [ + { + if: { + condition: { comp: [{ var: "i" }, ">=", 10] }, //if i >= 10 break loop + body: ["break"], + //else: [..commands] also work + }, + }, + { assign: { i: { calc: [{ var: "i" }, "+", 1] } } }, // i += 1 + { print: ["\ri = ", { var: "i" }] }, + { sleep: 500 }, //sleep 500 ms + ], + }, +] +``` + +## Input from console + +```json5 +[ + { + let: { + name: { input: "Your name: " }, + }, + }, + { print: ["Bye, ", { var: "name" }, "!"] }, +] +``` diff --git a/test.json5 b/example.json5 similarity index 83% rename from test.json5 rename to example.json5 index 4ca337f..9c7b92a 100644 --- a/test.json5 +++ b/example.json5 @@ -163,6 +163,7 @@ ["After executing calculated = ", { var: "calculated" }], "\nRun loop", + { loop: [ { @@ -174,10 +175,11 @@ loop: [ { if: { - condition: { comp: [{ var: "num" }, ">=", 200000] }, + condition: { comp: [{ var: "num" }, ">=", 100000] }, body: ["break"], }, }, + { assign: { num: { calc: [{ var: "num" }, "+", 1] }, @@ -203,7 +205,7 @@ }, { if: { - condition: { comp: [{ var: "calculated" }, ">=", 200000] }, + condition: { comp: [{ var: "calculated" }, ">=", 100000] }, body: ["\n", "break"], }, }, @@ -212,30 +214,43 @@ { if: { - condition: { comp: [{ var: "calculated" }, ">=", 199999] }, - body: [["Calculated is >= ", 199999]], - else: [["Calculated is < ", 199999]], + condition: { comp: [{ var: "calculated" }, ">=", 99999] }, + body: [["сalculated is >= ", 99999]], + else: [["сalculated is < ", 99999]], }, }, { if: { - condition: { comp: [{ var: "calculated" }, ">", 200000] }, - body: [["Calculated is > ", 200000]], - else: [["Calculated is <= ", 200000]], + condition: { comp: [{ var: "calculated" }, ">", 100000] }, + body: [["сalculated is > ", 100000]], + else: [["сalculated is <= ", 100000]], }, }, - "clear", + { let: { i: 0 } }, - // //TODO CONCEPTS ########################################################################################################################################################################################################################## + "\nLoop with sleep", - // { - // while: { - // cond: { comp: [1, ">=", {var: "variable"}] }, - // body: [ - // //commands - // ], - // }, - // }, + { + loop: [ + { + if: { + condition: { comp: [{ var: "i" }, ">=", 10] }, + body: ["break"], + }, + }, + { assign: { i: { calc: [{ var: "i" }, "+", 1] } } }, + { print: ["\ri = ", { var: "i" }] }, + { sleep: 500 }, + ], + }, + + "\nInput a var", + { + let: { + name: { input: "Your name: " }, + }, + }, + { print: ["Bye, ", { var: "name" }, "!"] }, ] diff --git a/src/interpreter.rs b/src/interpreter.rs index b2aa81b..46e357a 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -2,6 +2,8 @@ use colored::*; use json5; use serde_json::{json, Map, Value}; use std::collections::HashMap; +use std::io::{self, Write}; +use std::{thread, time}; pub struct Interpreter { input: String, vars: HashMap, @@ -18,8 +20,8 @@ impl Interpreter { } pub fn run(&mut self) { - let obj = json5::from_str::(&self.input).unwrap(); - let arr = obj.as_array().unwrap(); + let obj = json5::from_str::(&self.input).expect("Your json is invalid!"); + let arr = obj.as_array().expect("Json must be an array!"); for command in arr { self.eval_node(command); @@ -102,6 +104,22 @@ impl Interpreter { self.error("Unsupported data type for the let argument"); } }, + "input" => match value { + Value::String(value) => { + return self.input(value); + } + _ => { + self.error("Unsupported data type for the input argument"); + } + }, + "sleep" => match value { + Value::Number(value) => { + self.sleep(value); + } + _ => { + self.error("Unsupported data type for the sleep argument"); + } + }, "if" => match value { Value::Object(value) => { return self.if_node(value); @@ -150,10 +168,23 @@ impl Interpreter { return Value::Null; } + fn sleep(&self, value: &serde_json::Number) { + let value = value.as_f64().unwrap() as u64; + thread::sleep(time::Duration::from_millis(value)); + } + fn clear(&self) { print!("{}[2J", 27 as char); } + fn input(&self, value: &String) -> Value { + let mut input = String::new(); + print!("{}", value); + io::stdout().flush().unwrap_or_default(); + io::stdin().read_line(&mut input).unwrap_or_default(); + Value::String(input.trim_end().to_string()) + } + fn if_node(&mut self, value: &Map) -> Value { let condition = self.eval_node(&value["condition"]); let nodes = &value.get("body"); @@ -477,6 +508,7 @@ impl Interpreter { if ln == true { println!(); } + io::stdout().flush().unwrap_or_default(); } fn print_one(&mut self, arg: &Value) { diff --git a/src/main.rs b/src/main.rs index 5e7700b..a9452bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use clap::Parser; use std::fs; use std::time::Instant; - #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args {