mirror of
https://github.com/artegoser/ONLang
synced 2024-12-23 01:23:46 +03:00
feat: compressing files, converting files
and error message handling
This commit is contained in:
parent
30150961a9
commit
1da96d7704
4 changed files with 185 additions and 33 deletions
|
@ -21,5 +21,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
json5 = "0.4.1"
|
json5 = "0.4.1"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
|
rmp-serde = "1.1.0"
|
||||||
|
|
||||||
clap = { version = "3.2", features = ["derive"] }
|
clap = { version = "3.2", features = ["derive"] }
|
||||||
colored = "2"
|
colored = "2"
|
|
@ -74,5 +74,4 @@
|
||||||
// "21! == 51 090 942 171 709 440 000: ",
|
// "21! == 51 090 942 171 709 440 000: ",
|
||||||
// { _eq: [{ fact: [21] }, 51090942171709440000] },
|
// { _eq: [{ fact: [21] }, 51090942171709440000] },
|
||||||
// ], some json and yaml troubles with number `51090942171709440000`
|
// ], some json and yaml troubles with number `51090942171709440000`
|
||||||
{ calc: ["operand", "+", "operand"] }
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,10 +3,13 @@ use colored::*;
|
||||||
use json5;
|
use json5;
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::fs::File;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::{thread, time};
|
use std::path::Path;
|
||||||
|
use std::{fs, thread, time};
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
input: String,
|
commands: Vec<Value>,
|
||||||
vars: HashMap<String, Var>,
|
vars: HashMap<String, Var>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
scope: usize,
|
scope: usize,
|
||||||
|
@ -14,32 +17,159 @@ pub struct Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn new(input: String) -> Self {
|
pub fn new(file_path: String) -> Self {
|
||||||
|
match Path::new(&file_path)
|
||||||
|
.extension()
|
||||||
|
.and_then(OsStr::to_str)
|
||||||
|
.expect("The file must have the extension (.yaml, .json, .json5, .onla or .conla)")
|
||||||
|
{
|
||||||
|
"yaml" => {
|
||||||
|
let file_input = fs::read_to_string(&file_path).expect("File reading error");
|
||||||
|
let obj: serde_json::Value =
|
||||||
|
serde_yaml::from_str(&file_input).unwrap_or_else(|x| {
|
||||||
|
match x.location() {
|
||||||
|
Some(location) => {
|
||||||
|
eprintln!(
|
||||||
|
"{file_path}:{}:{} --> {x}",
|
||||||
|
location.column(),
|
||||||
|
location.line()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
eprintln!("{}", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
let commands = obj.as_array().unwrap_or_else(|| {
|
||||||
|
obj.get("main")
|
||||||
|
.expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])")
|
||||||
|
.as_array()
|
||||||
|
.expect("The program must be an array of commands")
|
||||||
|
});
|
||||||
Self {
|
Self {
|
||||||
input,
|
commands: commands.clone(),
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
pos: 1,
|
pos: 1,
|
||||||
scope: 0,
|
scope: 0,
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"conla" => {
|
||||||
pub fn run(&mut self) {
|
let file_input = File::open(file_path).expect("File reading error");
|
||||||
let obj: serde_json::Value = json5::from_str::<Value>(&self.input).unwrap_or_else(|_| {
|
let obj: serde_json::Value = rmp_serde::from_read(file_input)
|
||||||
serde_yaml::from_str(&self.input)
|
.expect(".conla file (MessagePack) is invalid! ");
|
||||||
.expect("Your file format is invalid! (supported: json, json5 or yaml)")
|
let commands = obj.as_array().unwrap_or_else(|| {
|
||||||
|
obj.get("main")
|
||||||
|
.expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])")
|
||||||
|
.as_array()
|
||||||
|
.expect("The program must be an array of commands")
|
||||||
});
|
});
|
||||||
let arr = obj.as_array().unwrap_or_else(|| {
|
Self {
|
||||||
|
commands: commands.clone(),
|
||||||
|
vars: HashMap::new(),
|
||||||
|
pos: 1,
|
||||||
|
scope: 0,
|
||||||
|
scopes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let file_input = fs::read_to_string(&file_path).expect("File reading error");
|
||||||
|
let obj: serde_json::Value =
|
||||||
|
json5::from_str::<Value>(&file_input).unwrap_or_else(|x| {
|
||||||
|
eprintln!("{file_path}{x}");
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
let commands = obj.as_array().unwrap_or_else(|| {
|
||||||
obj.get("main")
|
obj.get("main")
|
||||||
.expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])")
|
.expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])")
|
||||||
.as_array()
|
.as_array()
|
||||||
.expect("The program must be an array of commands")
|
.expect("The program must be an array of commands")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
commands: commands.clone(),
|
||||||
|
vars: HashMap::new(),
|
||||||
|
pos: 1,
|
||||||
|
scope: 0,
|
||||||
|
scopes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compress(&mut self, output_path: String) {
|
||||||
|
let mut output = File::create(output_path).expect("Failed to create output file");
|
||||||
|
output
|
||||||
|
.write_all(
|
||||||
|
&rmp_serde::encode::to_vec(&self.commands)
|
||||||
|
.expect("Error when compressing onlang to .conla"),
|
||||||
|
)
|
||||||
|
.expect("Error when writing to file");
|
||||||
|
println!("Compressed");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert(&self, format: String, output_path: String) {
|
||||||
|
match format.as_str() {
|
||||||
|
"yaml" => {
|
||||||
|
self.convert_to_yaml(output_path);
|
||||||
|
}
|
||||||
|
"json" => {
|
||||||
|
self.convert_to_json(output_path);
|
||||||
|
}
|
||||||
|
"json5" => {
|
||||||
|
self.convert_to_json5(output_path);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.error("The conversion format is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_to_yaml(&self, output_path: String) {
|
||||||
|
let mut output = File::create(output_path).expect("Failed to create output file");
|
||||||
|
write!(
|
||||||
|
output,
|
||||||
|
"{}",
|
||||||
|
serde_yaml::to_string(&self.commands).expect("Error when convert to yaml")
|
||||||
|
)
|
||||||
|
.expect("Error when writing to file");
|
||||||
|
|
||||||
|
println!("Converted");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_to_json(&self, output_path: String) {
|
||||||
|
let mut output = File::create(output_path).expect("Failed to create output file");
|
||||||
|
write!(
|
||||||
|
output,
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string(&self.commands).expect("Error when convert to json")
|
||||||
|
)
|
||||||
|
.expect("Error when writing to file");
|
||||||
|
|
||||||
|
println!("Converted");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_to_json5(&self, output_path: String) {
|
||||||
|
let mut output = File::create(output_path).expect("Failed to create output file");
|
||||||
|
write!(
|
||||||
|
output,
|
||||||
|
"{}",
|
||||||
|
json5::to_string(&self.commands).expect("Error when convert to json5")
|
||||||
|
)
|
||||||
|
.expect("Error when writing to file");
|
||||||
|
|
||||||
|
println!("Converted");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
self.scopes.push(Vec::new());
|
self.scopes.push(Vec::new());
|
||||||
for command in arr {
|
let length = self.commands.len();
|
||||||
|
for i in 0..length {
|
||||||
|
let command = &self.commands[i].clone();
|
||||||
self.eval_node(command);
|
self.eval_node(command);
|
||||||
self.pos += 1;
|
self.pos = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -1,40 +1,61 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::fs;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
mod types;
|
mod types;
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
file: String,
|
path: String,
|
||||||
|
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
|
|
||||||
|
#[clap(long)]
|
||||||
|
compress: bool,
|
||||||
|
|
||||||
|
#[clap(long)]
|
||||||
|
convert: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short, long)]
|
||||||
|
out: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
use interpreter::Interpreter;
|
use interpreter::Interpreter;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(not(debug_assertions))]
|
// #[cfg(not(debug_assertions))]
|
||||||
std::panic::set_hook(Box::new(|info| {
|
std::panic::set_hook(Box::new(|info| {
|
||||||
eprint!(
|
eprint!(
|
||||||
"{msg}",
|
"{}",
|
||||||
msg = match info.payload().downcast_ref::<String>() {
|
match info.payload().downcast_ref::<String>() {
|
||||||
None => "Program panicked without a message!",
|
None => "Program panicked without a message!",
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
if args.verbose == true {
|
if args.verbose == true {
|
||||||
println!("Running: {}\n", args.file);
|
println!("Running: {}\n", args.path);
|
||||||
}
|
}
|
||||||
let file_input = fs::read_to_string(args.file).expect("File reading error");
|
|
||||||
let mut onint = Interpreter::new(file_input);
|
|
||||||
|
|
||||||
|
let mut onint = Interpreter::new(args.path);
|
||||||
|
|
||||||
|
match args.out {
|
||||||
|
Some(output_path) => {
|
||||||
|
if args.compress {
|
||||||
|
onint.compress(output_path);
|
||||||
|
} else if let Some(format) = args.convert {
|
||||||
|
onint.convert(format, output_path);
|
||||||
|
} else {
|
||||||
|
eprintln!("The file conversion format is not specified, use the flag: --compress")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
onint.run();
|
onint.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args.verbose == true {
|
if args.verbose == true {
|
||||||
println!("\nElapsed: {:?}", start.elapsed());
|
println!("\nElapsed: {:?}", start.elapsed());
|
||||||
|
|
Loading…
Add table
Reference in a new issue