From 5a472f9b78233cae26d7ae2afeb5f8cd317743b9 Mon Sep 17 00:00:00 2001 From: Joshua Kidd Date: Mon, 5 Jan 2015 17:01:59 -0700 Subject: [PATCH] Initial Commit --- Cargo.lock | 4 ++ Cargo.toml | 5 ++ src/abs.rs | 17 +++++++ src/eval.rs | 64 ++++++++++++++++++++++++ src/main.rs | 44 ++++++++++++++++ src/parser.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/t01.hut | 6 +++ 7 files changed, 275 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/abs.rs create mode 100644 src/eval.rs create mode 100644 src/main.rs create mode 100644 src/parser.rs create mode 100644 tests/t01.hut diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d7b9792 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "Hut" +version = "0.0.1" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..86a6788 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[package] + +name = "Hut" +version = "0.0.1" +authors = ["Joshua Kidd ), + Plus(Box, Box), + Minus(Box, Box) +} \ No newline at end of file diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000..e3bc3fe --- /dev/null +++ b/src/eval.rs @@ -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); + +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), + } + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ffce718 --- /dev/null +++ b/src/main.rs @@ -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 { + let mut res: Vec = vec![]; + for line in s.as_slice().lines_any() { + match line { + "" => {} + _ => res.push(Line{content: line}) + } + } + return res; +} \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..c8a3942 --- /dev/null +++ b/src/parser.rs @@ -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 +} + +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) -> Vec { + let mut res: Vec = 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); + } +} \ No newline at end of file diff --git a/tests/t01.hut b/tests/t01.hut new file mode 100644 index 0000000..e2aef2c --- /dev/null +++ b/tests/t01.hut @@ -0,0 +1,6 @@ +a :: Int +a = 5 + +a1 :: Int +a1 = 222 +a1 = 333 \ No newline at end of file