Skip to content

Commit

Permalink
Add source
Browse files Browse the repository at this point in the history
  • Loading branch information
19wintersp committed Aug 14, 2021
1 parent 0a70ca6 commit 1dc80b5
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 0 deletions.
115 changes: 115 additions & 0 deletions Cargo.lock

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

9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "ook"
version = "0.1.0"
authors = [ "Patrick Winters <19wintersp@gmail.com>" ]
edition = "2018"
description = "A basic, customisable Ook interpreter"

[dependencies]
clap = "2.33.3"
31 changes: 31 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::process;

#[derive(Clone, Debug)]
pub struct Error {
message: String,
pos: (usize, usize),
line: String,
}

impl Error {
pub fn new(message: String, source: String, pos: (usize, usize)) -> Self {
Self {
message,
pos,
line: source.split("\n").nth(pos.1).unwrap().into(),
}
}

pub fn exit(self) -> ! {
self.display();
process::exit(2);
}

pub fn display(self) {
let numl = ((self.pos.1 + 1) as f32).log10() as usize + 1;

eprintln!("{}\n", self.message);
eprintln!(" {} | {}", self.pos.1 + 1, self.line);
eprintln!("{}^ here", "-".repeat(numl + self.pos.0 + 4));
}
}
59 changes: 59 additions & 0 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::error::Error;
use crate::{ Token, TokenType };

pub fn interpret(tokens: Vec<Token>, source: String) -> Result<(), Error> {
let len = tokens.len();

let mut mem = [ 0u8; 65536 ];
let mut ptr = 0usize;

let mut ip = 0usize;

let mut loops = Vec::<usize>::new();

loop {
if ip >= len { break }

match tokens[ip].token {
TokenType::PtrLeft => ptr -= 1,
TokenType::PtrRight => ptr += 1,
TokenType::Increment => mem[ptr] += 1,
TokenType::Decrement => mem[ptr] -= 1,
TokenType::Output => print!("{}", mem[ptr] as char),
TokenType::Input => unimplemented!(),
TokenType::LoopStart => {
if mem[ptr] == 0 {
let start = tokens[ip].pos;

loop {
ip += 1;

if ip >= len {
return Err(Error::new("Error: Unmatched loop start".into(), source, start))
}

if tokens[ip].token == TokenType::LoopEnd {
break
}
}
} else {
loops.push(ip);
}
},
TokenType::LoopEnd => {
if let Some(pos) = loops.last() {
if mem[ptr] != 0 {
ip = pos + 1;
continue
}
} else {
return Err(Error::new("Error: Unmatched loop end".into(), source, tokens[ip].pos))
}
},
}

ip += 1;
}

Ok(())
}
63 changes: 63 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
mod error;
mod interpreter;
mod token;
mod tokeniser;

use interpreter::interpret;
use token::{ Token, TokenType };
use tokeniser::{ Config, tokenise };

use std::fs;

use clap::{ clap_app, Error };

static TOKEN_A: &str = "Ook.";
static TOKEN_B: &str = "Ook!";
static TOKEN_C: &str = "Ook?";

fn main() {
let matches = clap_app!(app =>
(name: env!("CARGO_PKG_NAME"))
(version: env!("CARGO_PKG_VERSION"))
(author: env!("CARGO_PKG_AUTHORS"))
(about: env!("CARGO_PKG_DESCRIPTION"))
(@arg csin: -i --("case-insensitive") "Ignores case when matching tokens")
(@arg strict: -s --strict "Enables strict mode: only tokens are permitted")
(@arg token_a: -a --("token-a") +takes_value "Specify custom A token")
(@arg token_b: -b --("token-b") +takes_value "Specify custom B token")
(@arg token_c: -c --("token-c") +takes_value "Specify custom C token")
(@arg eval: -e --eval +takes_value "Specify script to execute instead of FILE")
(@arg FILE: +takes_value required_unless[eval] "File to execute")
).get_matches();

let strict = matches.is_present("strict");
let insensitive = matches.is_present("csin");

let token_a = matches.value_of("token_a").unwrap_or(TOKEN_A).into();
let token_b = matches.value_of("token_b").unwrap_or(TOKEN_B).into();
let token_c = matches.value_of("token_c").unwrap_or(TOKEN_C).into();

let code = if let Some(file) = matches.value_of("FILE") {
match fs::read_to_string(file) {
Ok(data) => data,
Err(err) => {
let err: Error = err.into();
err.exit();
},
}
} else {
matches.value_of("eval").unwrap().into()
};

let config = Config {
tokens: (token_a, token_b, token_c),
strict,
insensitive,
};

let tokens = tokenise(code.clone(), config)
.map_err(|err| err.exit())
.unwrap();
let _ = interpret(tokens, code)
.map_err(|err| err.exit());
}
23 changes: 23 additions & 0 deletions src/token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#[derive(Clone, Copy, Debug)]
pub struct Token {
pub token: TokenType,
pub pos: (usize, usize),
}

impl Token {
pub fn new(token: TokenType, pos: (usize, usize)) -> Self {
Self { token, pos }
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TokenType {
PtrRight,
PtrLeft,
Increment,
Decrement,
Output,
Input,
LoopStart,
LoopEnd,
}
Loading

0 comments on commit 1dc80b5

Please sign in to comment.