Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"crates/lexer",
"crates/parser",
"crates/interpreter",
"crates/interpreter2",
"crates/compiler",
"bins/lsp",
"bins/cli",
Expand All @@ -20,6 +21,7 @@ members = [
lexer = { path = "./crates/lexer" }
parser = { path = "./crates/parser" }
interpreter = { path = "./crates/interpreter" }
interpreter2 = { path = "./crates/interpreter2" }
compiler = { path = "./crates/compiler" }
vm = { path = "./crates/vm" }
cli = { path = "./bins/cli" }
Expand Down
1 change: 1 addition & 0 deletions bins/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ path = "src/main.rs"
lexer = { path = "../../crates/lexer" }
parser = { path = "../../crates/parser" }
interpreter = { path = "../../crates/interpreter" }
interpreter2 = { path = "../../crates/interpreter2" }
colored = "2.0.4"
clap = { version = "4.4.8", features = ["derive"] }
152 changes: 116 additions & 36 deletions bins/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
use interpreter::VType;
pub use lexer::*;
use clap::Parser;
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(help = "Path to file to run")]
path: std::path::PathBuf,
#[arg(short='c', long, default_value_t = false, help = "Disable colored output")]
no_colors: bool,
#[arg(short='v', long, default_value_t = false, help = "Enable verbose output")]
verbose: bool,
#[command(subcommand)]
command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
/// run a file
Run {
#[arg(help = "Path to file to run")]
path: std::path::PathBuf,
},
Run2 {
#[arg(help = "Path to file to run")]
path: std::path::PathBuf,
},
}

fn tokenize(text: &str) -> Result<Vec<Token>, PError> {
Expand All @@ -18,45 +32,111 @@ fn tokenize(text: &str) -> Result<Vec<Token>, PError> {

fn main() {
let args = Cli::parse();
let text = {
std::fs::read_to_string(args.path.clone()).unwrap_or_else(|e| {
eprintln!("{}", e);
std::process::exit(1);
})
};
let path = args.path.to_str().unwrap();
let colors = !args.no_colors;

if args.verbose {
println!("INPUT:\t{}\n", text);
}
let tokens = tokenize(&text).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path, colors));
if args.command.is_none() {
eprintln!("No command provided. Use --help for more information.");
std::process::exit(1);
});
if args.verbose {
println!("TOKENS:\t{}\n", TokenVec(&tokens));
}
let cmd = args.command.unwrap();
match cmd {
Commands::Run { path } => {
let path_str = path.to_str().unwrap();
let text = {
std::fs::read_to_string(path.clone()).unwrap_or_else(|e| {
eprintln!("{}", e);
std::process::exit(1);
})
};
if !path.exists() {
eprintln!("File not found: {}", path_str);
std::process::exit(1);
}
let colors = !args.no_colors;

let mut iter = tokens.iter();
let node = parser::parse(&mut iter).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path, colors));
std::process::exit(1);
});
if args.verbose {
println!("INPUT:\t{}\n", text);
}
let tokens = tokenize(&text).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path_str, colors));
std::process::exit(1);
});
if args.verbose {
println!("TOKENS:\t{}\n", TokenVec(&tokens));
}

if args.verbose {
println!("TREEs:\t{}\n", node);
}
let mut iter = tokens.iter();
let node = parser::parse(&mut iter).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path_str, colors));
std::process::exit(1);
});

if args.verbose {
println!("TREEs:\t{}\n", node);
}

if args.verbose {
println!("EXECUTING:");
}
let value = interpreter::interpret(node).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path, colors));
std::process::exit(1);
});
if args.verbose {
println!("EXECUTING:");
}
let value = interpreter::interpret(node).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path_str, colors));
std::process::exit(1);
});

println!("\nExited with code: {}", value);
if let VType::Undefined = value {
println!("\nExited with code: 0");
std::process::exit(0);
}
if let VType::Number(n)= value {
println!("\nExited with code: {}", n);
std::process::exit(n);
}
println!("\nExited with code: {}", value);
std::process::exit(0);
},
Commands::Run2 { path } => {
let path_str = path.to_str().unwrap();
let text = {
std::fs::read_to_string(path.clone()).unwrap_or_else(|e| {
eprintln!("{}", e);
std::process::exit(1);
})
};
if !path.exists() {
eprintln!("File not found: {}", path_str);
std::process::exit(1);
}
let colors = !args.no_colors;

if args.verbose {
println!("INPUT:\t{}\n", text);
}
let tokens = tokenize(&text).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path_str, colors));
std::process::exit(1);
});
if args.verbose {
println!("TOKENS:\t{}\n", TokenVec(&tokens));
}

let mut iter = tokens.iter();
let node = parser::parse(&mut iter).unwrap_or_else(|e| {
eprintln!("{}", e.format_error(&text, path_str, colors));
std::process::exit(1);
});

if args.verbose {
println!("TREEs:\t{}\n", node);
}

if args.verbose {
println!("EXECUTING:");
}
let value = interpreter2::interpret(node).unwrap_or_else(|e| {
eprintln!("{}", e);
std::process::exit(1);
});

std::process::exit(0);
},
}
}

2 changes: 1 addition & 1 deletion crates/compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{fmt::{Display, Formatter}};

use lexer::PError;
use parser::{Node, Op, Value};
use vm::{Instr, Instrs, OpCode};
use vm::{Instr, Instrs};


struct Code {
Expand Down
38 changes: 23 additions & 15 deletions crates/interpreter/src/builtins.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::fmt::Display;

use lexer::PError;
use lexer::{Location, PError};

use crate::vtype::VType;
use crate::{stack::StackFramePtr, vtype::VType};

pub struct Args<'a>(&'a Vec<VType>);
impl Display for Args<'_> {
Expand All @@ -22,6 +22,18 @@ pub enum Builtin {
Print,
Pow,
Assert,
Trace,
}

impl Display for Builtin {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Builtin::Print => write!(f, "print"),
Builtin::Pow => write!(f, "pow"),
Builtin::Assert => write!(f, "assert"),
Builtin::Trace => write!(f, "trace"),
}
}
}

impl Builtin {
Expand All @@ -30,44 +42,40 @@ impl Builtin {
"print" => Some(VType::Builtin(Builtin::Print)),
"pow" => Some(VType::Builtin(Builtin::Pow)),
"assert" => Some(VType::Builtin(Builtin::Assert)),
"trace" => Some(VType::Builtin(Builtin::Trace)),
_ => None,
}
}
pub fn includes(name: &str) -> bool {
match name {
"print" => true,
"pow" => true,
"assert" => true,
_ => false,
}
}
pub fn call(&self, args: &Vec<VType>) -> Result<VType, PError> {
pub fn call(&self, location: Location, args: &Vec<VType>, trace: &StackFramePtr) -> Result<VType, PError> {
match self{
Self::Print => {
println!("{}", Args(args));
Ok(VType::Undefined)
},
Self::Trace => {
Ok(VType::String(trace.borrow().stacktrace()))
},
Self::Pow => {
if args.len() != 2 {
return Err(PError::new(lexer::Location::zero(), "Expected 2 arguments"));
return Err(PError::new(location, "Expected 2 arguments"));
}
let a = args[0].clone();
let b = args[1].clone();
match (a, b) {
(VType::Number(a), VType::Number(b)) => Ok(VType::Number(a.pow(b as u32))),
_ => Err(PError::new(lexer::Location::zero(), "Expected numbers")),
_ => Err(PError::new(location, "Expected numbers")),
}
},
Self::Assert => {
let a = args[0].clone();
match a {
VType::Bool(b) => {
if !b {
return Err(PError::new(lexer::Location::zero(), "Assertion failed"));
return Err(PError::new(location, "Assertion failed"));
}
Ok(VType::Undefined)
},
_ => Err(PError::new(lexer::Location::zero(), "Expected boolean")),
_ => Err(PError::new(location, "Expected boolean")),
}

}
Expand Down
Loading
Loading