Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
g33kidd committed Jan 6, 2015
1 parent c6e39d1 commit 5a472f9
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]

name = "Hut"
version = "0.0.1"
authors = ["Joshua Kidd <[email protected]"]
17 changes: 17 additions & 0 deletions src/abs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#[derive(Show, Clone)]
pub struct Type(pub String);

#[derive(Show, Clone)]
pub enum Stm {
Vardef(Expr, Type),
Assign(Expr, Expr),
}

#[derive(Show, Clone)]
pub enum Expr {
Id(String),
LitInt(int),
Neg(Box<Expr>),
Plus(Box<Expr>, Box<Expr>),
Minus(Box<Expr>, Box<Expr>)
}
64 changes: 64 additions & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::collections::HashMap;

use abs::Expr;
use abs::Expr::{Id, LitInt, Neg, Plus, Minus};
use abs::Stm;
use abs::Stm::{Vardef, Assign};

#[derive(Show)]
struct Env(HashMap<String, int>);

impl Env {

fn new() -> Env {
return Env(HashMap::new());
}

fn add(&mut self, id: String, value: int) {
let ref mut m = self.0;
m.insert(id, value);
}

fn lookup(&mut self, id:String) -> int {
let ref mut m = self.0;
return *m.get(&id).expect("Undefined variable");
}

}

pub struct Eval {
env: Env,
}

impl Eval {

pub fn new() -> Eval {
Eval {env: Env::new()}
}

pub fn print_env(&self) {
println!("Environment:\n{}", self.env);
}

pub fn exec_stm(&mut self, stm: Stm) {
match stm {
Vardef(Id(_), _) => {},
Assign(Id(s), e) => {
let x = self.eval(e);
self.env.add(s, x)
},
_ => panic!("Unknown stm: {} in exec", stm)
};
}

fn eval(&mut self, expr: Expr) -> int {
match expr {
Id(s) => self.env.lookup(s),
LitInt(i) => i,
Neg(box e) => - self.eval(e),
Plus(box e1, box e2) => self.eval(e1) + self.eval(e2),
Minus(box e1, box e2) => self.eval(e1) - self.eval(e2),
}
}

}
44 changes: 44 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
extern crate regex;

use std::io::File;

use parser::{Line, Parser};
use eval::Eval;

mod abs;
mod parser;
mod eval;

fn main() {

let args = std::os::args();
if args.len() < 2 {
panic!("Please provide a file");
}

let path = Path::new(&args[1]);
let s = File::open(&path).read_to_string().unwrap();

let lines = preprocess(&s);

let p = Parser::new();
let stms = p.parse(lines);
println!("Parsed:\n{}\n", stms);

let mut e = Eval::new();
for stm in stms.iter() {
e.exec_stm((*stm).clone());
}
e.print_env();
}

fn preprocess<'a>(s: &'a String) -> Vec<Line> {
let mut res: Vec<Line> = vec![];
for line in s.as_slice().lines_any() {
match line {
"" => {}
_ => res.push(Line{content: line})
}
}
return res;
}
135 changes: 135 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use std::str::FromStr;
use regex::{Regex, Captures};

use abs::Expr::{self, Id, LitInt, Neg, Plus, Minus};
use abs::Stm::{self, Vardef, Assign};
use abs::Type;

#[derive(Show)]
pub struct Line<'a> {
pub content: &'a str
}

struct ParseRule {
name: String,
regex: Regex,
}
pub struct Parser {
rules: Vec<ParseRule>
}

impl Parser {

pub fn new() -> Parser {
let id = r"([:lower:][:alnum:]*)";
let typ = r"([:upper:][:alnum:]*)";
let litint = r"([:digit:]+)";
let expr = r"(.*)";

let parse_patterns = vec![
("Vardef", vec![id, r" :: ", typ]),
("Assign", vec![id, r" = ", expr]),

("Type", vec![typ]),

("Id", vec![id]),
("LitInt", vec![litint]),
("Plus", vec![expr, r" \+ ", expr]),
("Minus", vec![expr, r" - ", expr]),
("Neg", vec![r"-", expr]),
];

let mut rules = vec![];
for pp in parse_patterns.iter() {
let (name, ref pattern_parts) = *pp;
let mut regex_string = String::new();
regex_string.push_str("^");
for part in pattern_parts.iter() {
regex_string.push_str(*part);
}
regex_string.push_str("$");
let regex = Regex::new(regex_string.as_slice()).unwrap();
rules.push(ParseRule {name: String::from_str(name), regex: regex});
}
return Parser {rules: rules};
}

pub fn parse(&self, s: Vec<Line>) -> Vec<Stm> {
let mut res: Vec<Stm> = vec![];
for line in s.iter() {
let l = self.parse_stm((*line).content);
res.push(l);
}
return res;
}

fn parse_stm(&self, s: &str) -> Stm {
for rule in self.rules.iter() {
if rule.regex.is_match(s) {
let c = rule.regex.captures(s).expect("No captures");
return match rule.name.as_slice() {
"Vardef" => self.vardef(c),
"Assign" => self.assign(c),
_ => panic!("Bad match: {}", rule.name)
};
}
}
panic!("No match: {}", s);
}

fn vardef(&self, cap: Captures) -> Stm {
let e = self.parse_expr(cap.at(1).unwrap());
let t = cap.at(2).and_then(FromStr::from_str).unwrap();
return Vardef(e, Type(t));
}

fn assign(&self, cap: Captures) -> Stm {
let e1 = self.parse_expr(cap.at(1).unwrap());
let e2 = self.parse_expr(cap.at(2).unwrap());
return Assign(e1, e2);
}

fn parse_expr(&self, s: &str) -> Expr {
for rule in self.rules.iter() {
if rule.regex.is_match(s) {
let c = rule.regex.captures(s).expect("No captures");
return match rule.name.as_slice() {
"Id" => self.id(c),
"LitInt" => self.litint(c),
"Neg" => self.neg(c),
"Plus" => self.plus(c),
"Minus" => self.minus(c),
_ => panic!("Bad match: {}", rule.name)
};
}
}
panic!("No match: {}", s);
}

fn id(&self, cap: Captures) -> Expr {
let s = cap.at(1).and_then(FromStr::from_str).unwrap();
return Id(s);
}

fn litint(&self, cap: Captures) -> Expr {
let i = cap.at(1).and_then(FromStr::from_str).unwrap();
return LitInt(i);
}

fn neg(&self, cap: Captures) -> Expr {
let e = self.parse_expr(cap.at(1).unwrap());
return Neg(box e);
}

fn plus(&self, cap: Captures) -> Expr {
let e1 = self.parse_expr(cap.at(1).unwrap());
let e2 = self.parse_expr(cap.at(2).unwrap());
return Plus(box e1, box e2);
}

fn minus(&self, cap: Captures) -> Expr {
let e1 = self.parse_expr(cap.at(1).unwrap());
let e2 = self.parse_expr(cap.at(2).unwrap());
return Minus(box e1, box e2);
}
}
6 changes: 6 additions & 0 deletions tests/t01.hut
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
a :: Int
a = 5

a1 :: Int
a1 = 222
a1 = 333

0 comments on commit 5a472f9

Please sign in to comment.