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:
parent
4a7b570603
commit
328ec4ba87
@ -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,
|
||||||
|
21
src/eval.rs
21
src/eval.rs
@ -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());
|
||||||
|
@ -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();
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user