-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
275 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
a :: Int | ||
a = 5 | ||
|
||
a1 :: Int | ||
a1 = 222 | ||
a1 = 333 |