Convertd like half the Strings to RC

-still need to eliminate some clones in eval, parse
+ fix all the tests
This commit is contained in:
greg 2017-01-04 04:18:55 -08:00
parent 4a7b570603
commit 328ec4ba87
4 changed files with 35 additions and 32 deletions

View File

@ -123,11 +123,11 @@ impl CodeGen for Expression {
let int_type = LLVMWrap::Int64TypeInContext(data.context); let int_type = LLVMWrap::Int64TypeInContext(data.context);
match self { match self {
&Variable(ref name) => *data.variables.get(name).unwrap(), &Variable(ref name) => *data.variables.get(&**name).unwrap(),
&BinExp(ref op, ref left, ref right) if op == "=" => { &BinExp(ref op, ref left, ref right) if **op == "=" => {
if let Variable(ref name) = **left { if let Variable(ref name) = **left {
let new_value = right.codegen(data); let new_value = right.codegen(data);
data.variables.insert(name.clone(), new_value); data.variables.insert((**name).clone(), new_value);
new_value new_value
} else { } else {
panic!("Bad variable assignment") panic!("Bad variable assignment")
@ -136,7 +136,7 @@ impl CodeGen for Expression {
&BinExp(ref op, ref left, ref right) => { &BinExp(ref op, ref left, ref right) => {
let lhs = left.codegen(data); let lhs = left.codegen(data);
let rhs = right.codegen(data); let rhs = right.codegen(data);
let generator = match op.as_ref() { let generator = match op.as_ref().as_ref() {
"+" => LLVMWrap::BuildAdd, "+" => LLVMWrap::BuildAdd,
"-" => LLVMWrap::BuildSub, "-" => LLVMWrap::BuildSub,
"*" => LLVMWrap::BuildMul, "*" => LLVMWrap::BuildMul,

View File

@ -2,6 +2,7 @@ extern crate take_mut;
use std::collections::HashMap; use std::collections::HashMap;
use parser::{AST, Statement, Expression, Function}; use parser::{AST, Statement, Expression, Function};
use std::rc::Rc;
type Reduction<T> = (T, Option<SideEffect>); type Reduction<T> = (T, Option<SideEffect>);
@ -94,7 +95,7 @@ impl Expression {
use parser::Expression::*; use parser::Expression::*;
match *self { match *self {
Null => false, Null => false,
StringLiteral(ref s) if s == "" => false, StringLiteral(ref s) if **s == "" => false,
Number(0.0) => false, Number(0.0) => false,
_ => true, _ => true,
} }
@ -128,7 +129,7 @@ impl<'a> Evaluator<'a> {
self.add_binding(var, value); self.add_binding(var, value);
}, },
AddFunctionBinding(function) => { AddFunctionBinding(function) => {
self.add_function(function.prototype.name.clone(), function); self.add_function((*function.prototype.name).clone(), function);
} }
} }
} }
@ -171,10 +172,10 @@ impl<'a> Evaluator<'a> {
} }
// special case for variable assignment // special case for variable assignment
if op == "=" { if *op == "=" {
match left { match left {
Variable(var) => { Variable(var) => {
let binding = SideEffect::AddBinding(var, right); let binding = SideEffect::AddBinding((*var).clone(), right);
return (Null, Some(binding)); return (Null, Some(binding));
} }
_ => return (Null, None), _ => return (Null, None),
@ -243,13 +244,13 @@ impl<'a> Evaluator<'a> {
} }
} }
fn reduce_binop(&mut self, op: String, left: Expression, right: Expression) -> Expression { fn reduce_binop(&mut self, op: Rc<String>, left: Expression, right: Expression) -> Expression {
use parser::Expression::*; use parser::Expression::*;
let truthy = Number(1.0); let truthy = Number(1.0);
let falsy = Null; let falsy = Null;
match (&op[..], left, right) { match (&op[..], left, right) {
("+", Number(l), Number(r)) => Number(l + r), ("+", Number(l), Number(r)) => Number(l + r),
("+", StringLiteral(s1), StringLiteral(s2)) => StringLiteral(format!("{}{}", s1, s2)), ("+", StringLiteral(s1), StringLiteral(s2)) => StringLiteral(Rc::new(format!("{}{}", *s1, *s2))),
("-", Number(l), Number(r)) => Number(l - r), ("-", Number(l), Number(r)) => Number(l - r),
("*", Number(l), Number(r)) => Number(l * r), ("*", Number(l), Number(r)) => Number(l * r),
("/", Number(l), Number(r)) if r != 0.0 => Number(l / r), ("/", Number(l), Number(r)) if r != 0.0 => Number(l / r),
@ -266,12 +267,12 @@ impl<'a> Evaluator<'a> {
} }
} }
fn reduce_call(&mut self, name: String, arguments: Vec<Expression>) -> Reduction<Expression> { fn reduce_call(&mut self, name: Rc<String>, arguments: Vec<Expression>) -> Reduction<Expression> {
use parser::Expression::*; use parser::Expression::*;
use parser::Statement::*; use parser::Statement::*;
// ugly hack for now // ugly hack for now
if name == "print" { if *name == "print" {
let mut s = String::new(); let mut s = String::new();
for arg in arguments { for arg in arguments {
s.push_str(&format!("{}\n", arg)); s.push_str(&format!("{}\n", arg));
@ -279,7 +280,7 @@ impl<'a> Evaluator<'a> {
return (Null, Some(SideEffect::Print(s))); return (Null, Some(SideEffect::Print(s)));
} }
let function = match self.lookup_function(name) { let function = match self.lookup_function((*name).clone()) {
Some(func) => func, Some(func) => func,
None => return (Null, None), None => return (Null, None),
}; };
@ -290,7 +291,7 @@ impl<'a> Evaluator<'a> {
let mut evaluator = Evaluator::new(Some(self)); let mut evaluator = Evaluator::new(Some(self));
for (binding, expr) in function.prototype.parameters.iter().zip(arguments.iter()) { for (binding, expr) in function.prototype.parameters.iter().zip(arguments.iter()) {
evaluator.add_binding(binding.clone(), expr.clone()); evaluator.add_binding((**binding).clone(), expr.clone());
} }
let nodes = function.body.iter().map(|node| node.clone()); let nodes = function.body.iter().map(|node| node.clone());

View File

@ -1,6 +1,7 @@
use std::fmt; use std::fmt;
use tokenizer::{Token, Kw, Op}; use tokenizer::{Token, Kw, Op};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::rc::Rc;
// Grammar // Grammar
// program := (statement delimiter ?)* // program := (statement delimiter ?)*
@ -46,18 +47,18 @@ pub struct Function {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Prototype { pub struct Prototype {
pub name: String, pub name: Rc<String>,
pub parameters: Vec<String>, pub parameters: Vec<Rc<String>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expression { pub enum Expression {
Null, Null,
StringLiteral(String), StringLiteral(Rc<String>),
Number(f64), Number(f64),
Variable(String), Variable(Rc<String>),
BinExp(String, Box<Expression>, Box<Expression>), BinExp(Rc<String>, Box<Expression>, Box<Expression>),
Call(String, Vec<Expression>), Call(Rc<String>, Vec<Expression>),
Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>), Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>),
Lambda(Function), Lambda(Function),
Block(VecDeque<Expression>), Block(VecDeque<Expression>),
@ -218,9 +219,9 @@ impl Parser {
fn prototype(&mut self) -> ParseResult<Prototype> { fn prototype(&mut self) -> ParseResult<Prototype> {
use tokenizer::Token::*; use tokenizer::Token::*;
let name: String = expect_identifier!(self); let name: Rc<String> = expect_identifier!(self);
expect!(self, LParen); expect!(self, LParen);
let parameters: Vec<String> = try!(self.identlist()); let parameters: Vec<Rc<String>> = try!(self.identlist());
expect!(self, RParen); expect!(self, RParen);
Ok(Prototype { Ok(Prototype {
name: name, name: name,
@ -228,11 +229,11 @@ impl Parser {
}) })
} }
fn identlist(&mut self) -> ParseResult<Vec<String>> { fn identlist(&mut self) -> ParseResult<Vec<Rc<String>>> {
use tokenizer::Token::*; use tokenizer::Token::*;
let mut args: Vec<String> = Vec::new(); let mut args: Vec<Rc<String>> = Vec::new();
while let Some(Identifier(name)) = self.peek() { while let Some(Identifier(name)) = self.peek() {
args.push(name); args.push(name.clone());
self.next(); self.next();
if let Some(Comma) = self.peek() { if let Some(Comma) = self.peek() {
self.next(); self.next();

View File

@ -3,6 +3,7 @@ extern crate itertools;
use std::iter::Peekable; use std::iter::Peekable;
use std::str::Chars; use std::str::Chars;
use self::itertools::Itertools; use self::itertools::Itertools;
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Token { pub enum Token {
@ -14,14 +15,14 @@ pub enum Token {
Period, Period,
Colon, Colon,
NumLiteral(f64), NumLiteral(f64),
StrLiteral(String), StrLiteral(Rc<String>),
Identifier(String), Identifier(Rc<String>),
Operator(Op), Operator(Op),
Keyword(Kw), Keyword(Kw),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Op(pub String); pub struct Op(pub Rc<String>);
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Kw { pub enum Kw {
@ -92,14 +93,14 @@ fn tokenize_str(iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> {
None => return Err(TokenizeError::new("Unclosed quote")), None => return Err(TokenizeError::new("Unclosed quote")),
} }
} }
Ok(Token::StrLiteral(buffer)) Ok(Token::StrLiteral(Rc::new(buffer)))
} }
fn tokenize_operator(c: char, iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> { fn tokenize_operator(c: char, iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> {
let mut buffer = String::new(); let mut buffer = String::new();
buffer.push(c); buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| !char::is_alphanumeric(*x) && !char::is_whitespace(*x))); buffer.extend(iter.peeking_take_while(|x| !char::is_alphanumeric(*x) && !char::is_whitespace(*x)));
Ok(Token::Operator(Op(buffer))) Ok(Token::Operator(Op(Rc::new(buffer))))
} }
fn tokenize_number_or_period(c: char, iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> { fn tokenize_number_or_period(c: char, iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> {
@ -138,7 +139,7 @@ fn tokenize_identifier(c: char, iter: &mut Peekable<Chars>) -> Result<Token, Tok
"let" => Keyword(Kw::Let), "let" => Keyword(Kw::Let),
"fn" => Keyword(Kw::Fn), "fn" => Keyword(Kw::Fn),
"null" => Keyword(Kw::Null), "null" => Keyword(Kw::Null),
b => Identifier(b.to_string()), b => Identifier(Rc::new(b.to_string())),
}) })
} }
@ -181,7 +182,7 @@ mod tests {
#[test] #[test]
fn string_test() { fn string_test() {
token_test!("null + \"a string\"", token_test!("null + \"a string\"",
[Keyword(Kw::Null), Operator(Op(ref a)), StrLiteral(ref b)], [Keyword(Kw::Null), Operator(Op(ref a)), StrgLiteral(ref b)],
a == "+" && b == "a string"); a == "+" && b == "a string");
} }