Skip to content

Instantly share code, notes, and snippets.

@pythonesque
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pythonesque/e0bd89f00f64c66de081 to your computer and use it in GitHub Desktop.
Save pythonesque/e0bd89f00f64c66de081 to your computer and use it in GitHub Desktop.
#![feature(overloaded_calls)]
pub struct G<T, U> {
n: T,
}
impl<T: Add<U, T> + Clone, U> FnMut<(U,), T> for G<T, U> {
extern "rust-call" fn call_mut(&mut self, (i,):(U,)) -> T {
self.n = self.n + i;
self.n.clone()
}
}
pub fn accum<T: Add<T, U> + Clone, U>(n: T) -> G<T, U> {
G { n: n }
}
fn main() {
// Deviation: works with all types implementing addition, but not a mixture
// of types (it is possible to handle mixed types, but would require type
// switching at the moment).
let mut g = accum(1f32);
g(5.);
accum(3i32);
println!("{}", g(2.3));
}
// Implements http://rosettacode.org/wiki/S-Expressions
extern crate arena;
use arena::TypedArena;
use std::io;
use std::num;
use std::char;
use std::string;
#[deriving(Show)]
enum SExp<'a> {
F64(f64),
List(&'a [SExp<'a>]),
Str(&'a str),
}
#[deriving(Eq,PartialEq,Show)]
pub enum Error {
NoReprForFloat,
StackUnderflow,
UnterminatedStringLiteral,
IoError(io::IoError),
InternalError,
IncorrectCloseDelimiter,
UnexpectedEOF,
ExpectedEOF,
}
#[deriving(Eq,PartialEq,Show)]
enum Token<'a> {
ListStart,
ListEnd,
Literal(&'a str),
EOF,
}
#[deriving(Show)]
struct Tokens<'a> {
first: Option<char>,
rest: &'a str,
}
impl<'a> Tokens<'a> {
fn new(string: &str) -> Tokens {
let (ch, s) = string.slice_shift_char();
Tokens { first: ch, rest: string }
}
fn next(&mut self) -> Result<Token<'a>, Error> {
loop {
let (ch, s) = self.rest.slice_shift_char();
match ch {
// List start
Some('(') => {
self.rest = s;
return Ok(ListStart)
},
// List end
Some(')') => {
self.rest = s;
return Ok(ListEnd)
},
// Quoted literal start
Some('"') => {
// Split the string at most once. This lets us get a
// reference to the next piece of the string without having
// to loop through the string again.
let mut iter = s.splitn(1, '"');
let str = match iter.next() {
Some(s) => s,
None => return Err(InternalError)
};
match iter.next() {
Some(s) => {
self.rest = s;
return Ok(Literal(str))
},
None => return Err(UnterminatedStringLiteral)
}
},
Some(ch) => {
// TODO: Detect digits
// Skip whitespace
if ch.is_whitespace() {
self.rest = s;
continue
}
/*// Since we've exhausted all other possibilities, this must
// be an atom. Unlike the quoted case, it's not an error to
// encounter EOF before whitespace.
let mut end_ch = None;
let str = {
let mut iter = self.rest.splitn(1, |ch: char| {
let term = ch == ')' || ch == '(' || ch.is_whitespace();
if term { end_ch = Some(ch) }
term
});
let str = match iter.next() {
Some(s) => s,
None => return Err(InternalError)
};
self.rest = iter.next().unwrap_or("");
str
};
match end_ch {
Some(ch) => self.first = end_ch,
None => {
let (first, rest) = self.rest.slice_shift_char();
self.first = first;
self.rest = rest;
}
}*/
// Since we've exhausted all other possibilities, this must
// be an atom. Unlike the quoted case, it's not an error to
// encounter EOF before whitespace.
let mut end_ch = ch;
let mut iter = self.rest.splitn(1, |ch: char| {
end_ch = ch;
ch == ')' || ch == '(' || ch.is_whitespace()
});
let str = match iter.next() {
Some(s) => s,
None => return Err(InternalError)
};
self.rest = iter.next().unwrap_or("");
return Ok(Literal(str));
}
None => return Ok(EOF)
}
}
}
}
fn from_io_result<T>(res: io::IoResult<T>) -> Result<T, Error> {
res.map_err( |err| IoError(err) )
}
impl<'a> SExp<'a> {
pub fn encode<T: io::Writer>(&self, writer: &mut T) -> Result<(), Error> {
match *self {
F64(f) => match f.classify() {
num::FPNormal | num::FPZero => from_io_result(write!(writer, "{}", f)),
_ => Err(NoReprForFloat)
},
List(ref l) => {
try!(from_io_result(writer.write_char('(')))
let mut iter = l.iter();
match iter.next() {
Some(sexp) => {
try!(sexp.encode(writer));
for sexp in iter {
try!(from_io_result(writer.write_char(' ')));
try!(sexp.encode(writer));
}
},
None => (),
}
from_io_result(writer.write_char(')'))
},
Str(s) => from_io_result(write!(writer, "\"{}\"", s)),
}
}
pub fn parse(string: &str) -> Result<SExp, Error> {
let arena = TypedArena::new();
let mut tokens = Tokens::new(string);
let next = tokens.next();
let mut list = match try!(next) {
ListStart => Vec::<SExp>::new(),
Literal(s) => if try!(tokens.next()) == EOF { return Ok(Str(s)) } else { return Err(ExpectedEOF) },
ListEnd => return Err(IncorrectCloseDelimiter),
EOF => return Err(UnexpectedEOF),
};
// We know we're in a list if we got this far.
let mut stack = Vec::new();
loop {
let tok = tokens.next();
println!("{} ({})", tok, ::std::mem::size_of::<Token>());
match try!(tok) {
ListStart => {
stack.push(list);
list = Vec::new()
},
Literal(s) => list.push(Str(s)),
ListEnd => match stack.pop() {
Some(mut l) => {
l.push(List(arena.alloc(list)[]));
println!("{}", l);
list = l;
},
None => return Err(StackUnderflow),
},
EOF => return Ok(F64(0.0)),
}
}
}
pub fn buffer_encode(&self) -> Result<String, Error> {
let mut m = io::MemWriter::new();
try!(self.encode(&mut m));
// Because encode() only ever writes valid UTF-8, we can safely skip the secondary check we
// normally have to do when converting from Vec<u8> to String. If we didn't know that the
// buffer was already UTF-8, we'd want to call container_as_str() here.
unsafe { Ok(string::raw::from_utf8(m.unwrap())) }
}
}
static sexp_struct: SExp<'static> = List([
List([Str("data"), Str("quoted data"), F64(123.), F64(4.5)]),
List([List([Str("!@#"), List([F64(4.5)]), Str("(more"), Str("data)")])]),
]);
static sexp_string: &'static str = r#"(("data" "quoted data" 123 4.5) (("!@#" (4.5) "(more" "data)")))"#;
fn try_encode() -> Result<String, Error> {
sexp_struct.buffer_encode()
}
fn try_decode<'a>() -> Result<SExp<'a>, Error> {
SExp::parse(sexp_string)
}
#[cfg(not(test))]
fn main() {
println!("{}", try_encode());
println!("{}", try_decode());
}
#[test]
fn test() {
assert_eq!(Ok(sexp_string), try_encode().as_ref().map( |s| s[]));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment