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

View File

@ -2,6 +2,7 @@ extern crate take_mut;
use std::collections::HashMap;
use parser::{AST, Statement, Expression, Function};
use std::rc::Rc;
type Reduction<T> = (T, Option<SideEffect>);
@ -94,7 +95,7 @@ impl Expression {
use parser::Expression::*;
match *self {
Null => false,
StringLiteral(ref s) if s == "" => false,
StringLiteral(ref s) if **s == "" => false,
Number(0.0) => false,
_ => true,
}
@ -128,7 +129,7 @@ impl<'a> Evaluator<'a> {
self.add_binding(var, value);
},
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
if op == "=" {
if *op == "=" {
match left {
Variable(var) => {
let binding = SideEffect::AddBinding(var, right);
let binding = SideEffect::AddBinding((*var).clone(), right);
return (Null, Some(binding));
}
_ => 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::*;
let truthy = Number(1.0);
let falsy = Null;
match (&op[..], left, right) {
("+", 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)) 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::Statement::*;
// ugly hack for now
if name == "print" {
if *name == "print" {
let mut s = String::new();
for arg in arguments {
s.push_str(&format!("{}\n", arg));
@ -279,7 +280,7 @@ impl<'a> Evaluator<'a> {
return (Null, Some(SideEffect::Print(s)));
}
let function = match self.lookup_function(name) {
let function = match self.lookup_function((*name).clone()) {
Some(func) => func,
None => return (Null, None),
};
@ -290,7 +291,7 @@ impl<'a> Evaluator<'a> {
let mut evaluator = Evaluator::new(Some(self));
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());

View File

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

View File

@ -3,6 +3,7 @@ extern crate itertools;
use std::iter::Peekable;
use std::str::Chars;
use self::itertools::Itertools;
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
@ -14,14 +15,14 @@ pub enum Token {
Period,
Colon,
NumLiteral(f64),
StrLiteral(String),
Identifier(String),
StrLiteral(Rc<String>),
Identifier(Rc<String>),
Operator(Op),
Keyword(Kw),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Op(pub String);
pub struct Op(pub Rc<String>);
#[derive(Debug, Clone, PartialEq)]
pub enum Kw {
@ -92,14 +93,14 @@ fn tokenize_str(iter: &mut Peekable<Chars>) -> Result<Token, TokenizeError> {
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> {
let mut buffer = String::new();
buffer.push(c);
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> {
@ -138,7 +139,7 @@ fn tokenize_identifier(c: char, iter: &mut Peekable<Chars>) -> Result<Token, Tok
"let" => Keyword(Kw::Let),
"fn" => Keyword(Kw::Fn),
"null" => Keyword(Kw::Null),
b => Identifier(b.to_string()),
b => Identifier(Rc::new(b.to_string())),
})
}
@ -181,7 +182,7 @@ mod tests {
#[test]
fn string_test() {
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");
}