-
-
Save durka/23c0680d5581a14ca8c05436e1ed4b36 to your computer and use it in GitHub Desktop.
RustFest lightning talk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![no_std] | |
| pub mod prelude; | |
| #[macro_export] macro_rules! lisp { | |
| // empty | |
| () => (()); | |
| (()) => (()); | |
| // special forms | |
| ((ns $($ns_form:tt)*) $($body:tt)*) => { | |
| $(lisp!($ns_form);)* | |
| $(lisp!($body);)* | |
| }; | |
| ((extern [$($krate:tt)*])) => { | |
| $(lisp!(@krate $krate);)* | |
| }; | |
| ((use [$($uze:tt)*])) => { | |
| $(lisp!(@uze $uze);)* | |
| }; | |
| ((lambda ($($argn:ident)*) $($body:tt)*)) => { | |
| // regular lambda | |
| |$($argn),*| { $(lisp!($body));* } | |
| }; | |
| ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => { | |
| // regular lambda | |
| |$($argn:$argt),*| -> $ret { $(lisp!($body));* } | |
| }; | |
| ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{ | |
| // recursive lambda | |
| // $s MUST NOT be "self" | |
| // recurse by calling ($s ...) | |
| // FIXME recursive lambdas can't capture variables | |
| lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s })) | |
| }}; | |
| ((defn $name:ident () $($body:tt)*)) => { | |
| fn $name() { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => { | |
| fn $name($selph $(, $argn:$argt)*) -> $ret { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => { | |
| fn $name(&$selph $(, $argn:$argt)*) -> $ret { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => { | |
| fn $name(&mut $selph $(, $argn:$argt)*) -> $ret { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => { | |
| fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => { | |
| fn $name($($argn:$argt),*) -> $ret { | |
| $(lisp!($body));* | |
| } | |
| }; | |
| ((defstruct $name:ident $(($typ:ty))*)) => { | |
| struct $name($($typ),*); | |
| }; | |
| ((defstruct $name:ident $(($field:ident $typ:ty))*)) => { | |
| struct $name { $($field: $typ),* } | |
| }; | |
| ((defstruct $name:ident <$($gen:ident)*>)) => { | |
| struct $name<$($gen),*>; | |
| }; | |
| ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => { | |
| struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*; | |
| }; | |
| ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => { | |
| struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* } | |
| }; | |
| ((deftype $name:ident $typ:ty)) => { type $name = $typ; }; | |
| ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; }; | |
| ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => { | |
| impl $trate for $typ { | |
| $(lisp!($body);)* | |
| } | |
| }; | |
| ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => { | |
| impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* { | |
| $(lisp!($body);)* | |
| } | |
| }; | |
| ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => { | |
| impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* { | |
| $(lisp!($body);)* | |
| } | |
| }; | |
| ((if $cond:tt $yes:tt $no:tt)) => { | |
| if lisp!($cond) { lisp!($yes) } else { lisp!($no) } | |
| }; | |
| ((while $cond:tt $($body:tt)*)) => { | |
| while lisp!($cond) { $(lisp!($body));* } | |
| }; | |
| // TODO for loops | |
| ((match $var:tt $(($cond:pat) $arm:tt)*)) => { | |
| match lisp!($var) { | |
| $($cond => lisp!($arm)),* | |
| } | |
| }; | |
| ((do $($stmts:tt)*)) => {{ | |
| $(lisp!($stmts));* | |
| }}; | |
| // variables | |
| ((let [] $($body:tt)*)) => {{ | |
| $(lisp!($body));* | |
| }}; | |
| ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{ | |
| let mut $var = lisp!($val); | |
| lisp!((let [$($bindings)*] $($body)*)) | |
| }}; | |
| ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{ | |
| let $var = lisp!($val); | |
| lisp!((let [$($bindings)*] $($body)*)) | |
| }}; | |
| ((:= $var:ident $val:tt)) => { | |
| $var = lisp!($val); | |
| }; | |
| // escape hatch | |
| ((rust $body:block)) => { | |
| { $body } | |
| }; | |
| // list parsing | |
| (($($elem:tt)*)) => { | |
| lisp!(@list $($elem),*) | |
| }; | |
| // parsers for unary and binary operators | |
| (@list -, $arg:tt ) => { lisp!(@unary _neg, $arg ) }; | |
| (@list !, $arg:tt ) => { lisp!(@unary _not, $arg ) }; | |
| (@list +, $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) }; | |
| (@list &, $arg:tt) => { &lisp!($arg) }; | |
| (@list &, $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) }; | |
| (@list |, $($arg:tt),*) => { lisp!(@binary _or, $($arg),*) }; | |
| (@list ^, $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) }; | |
| (@list /, $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) }; | |
| (@list *, $arg:tt) => { *lisp!($arg) }; | |
| (@list *, $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) }; | |
| (@list %, $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) }; | |
| (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) }; | |
| (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) }; | |
| (@list -, $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) }; | |
| (@list ==, $($arg:tt),*) => { lisp!(@binary _eq, $($arg),*) }; | |
| (@list !=, $($arg:tt),*) => { lisp!(@binary _ne, $($arg),*) }; | |
| (@list >, $($arg:tt),*) => { lisp!(@binary _gt, $($arg),*) }; | |
| (@list <, $($arg:tt),*) => { lisp!(@binary _lt, $($arg),*) }; | |
| (@list >=, $($arg:tt),*) => { lisp!(@binary _ge, $($arg),*) }; | |
| (@list <=, $($arg:tt),*) => { lisp!(@binary _le, $($arg),*) }; | |
| // generically turn unary/binary operators into function calls | |
| // binary operators can be used as n-ary operators through @reduce | |
| (@unary $op:ident, $a:tt) => { lisp!(@list $op, $a) }; | |
| (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) }; | |
| (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) => | |
| { lisp!(@reduce $op, | |
| ($op $a $b), | |
| $($rest),+) }; | |
| // reduce implementation | |
| // TODO external entry point for @reduce | |
| (@reduce $op:ident, $acc:tt) => { lisp!($acc) }; | |
| (@reduce $op:ident, $acc:tt, $a:tt) => { lisp!(@reduce $op, | |
| ($op $acc $a)) }; | |
| (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op, | |
| ($op $acc $a), | |
| $($rest),+) }; | |
| // ns form helpers | |
| (@krate $(^$attr:meta)* $krate:ident) => { | |
| $(#[$attr:meta])* | |
| extern crate $krate; | |
| }; | |
| (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => { | |
| $(#[$attr:meta])* | |
| extern crate $krate as $alias; | |
| }; | |
| (@uze ($($head:ident)*)) => { use $($head)::*; }; | |
| (@uze ($($head:ident)* { $($multiple:ident)* })) => { | |
| lisp!(@uze mult ($($head)*) { $($multiple)* }); | |
| }; | |
| (@uze mult $head:tt { $($multiple:ident)* }) => { | |
| $(lisp!(@uze mult out $head $multiple);)* | |
| }; | |
| (@uze mult out ($($head:ident)*) $multiple:ident) => { | |
| use $($head)::*::$multiple; | |
| }; | |
| // macro calls | |
| (@list $mac:ident, !) => { | |
| $mac!() | |
| }; | |
| (@list $mac:ident, !, $($arg:tt),*) => { | |
| $mac!($(lisp!($arg)),*) | |
| }; | |
| // struct constructors | |
| (@list (:: $($name:tt)*), . $(, ($member:ident $val:tt))*) => { | |
| $($name)* { $($member: lisp!($val))* } | |
| }; | |
| (@list $name:ident, . $(, ($member:ident $val:tt))*) => { | |
| $name { $($member: lisp!($val))* } | |
| }; | |
| // function calls | |
| (@list (:: $name:path) $(, $arg:tt),*) => { | |
| $name($(lisp!($arg)),*) | |
| }; | |
| (@list $name:expr $(, $arg:tt)*) => { | |
| lisp!($name)($(lisp!($arg)),*) | |
| }; | |
| // method calls | |
| (@list ., $name:ident, $subj:tt $(, $arg:tt)*) => { | |
| lisp!($subj).$name($(lisp!($arg)),*) | |
| }; | |
| // one expression | |
| ($e:expr) => ($e); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #[macro_use] extern crate macrolisp; | |
| use macrolisp::prelude::*; | |
| lisp! { | |
| (ns | |
| (extern [bytes futures | |
| tokio_io | |
| tokio_proto | |
| tokio_service]) | |
| (use [(std {io str}) | |
| (bytes BytesMut) | |
| (futures {future Future BoxFuture}) | |
| (tokio_io {AsyncRead AsyncWrite}) | |
| (tokio_io codec {Encoder Decoder Framed}) | |
| (tokio_proto TcpServer) | |
| (tokio_proto pipeline ServerProto) | |
| (tokio_service Service)])) | |
| (defstruct LineCodec) | |
| (defstruct LineProto) | |
| (defstruct Echo) | |
| (defimpl (LineCodec: Decoder) | |
| (deftype Item String) | |
| (deftype Error io::Error) | |
| (defn decode (((self &mut Self) (buf &mut BytesMut)) | |
| io::Result<Option<String>>) | |
| (match (.position (.iter buf) | |
| (lambda (b) | |
| (== (* b) | |
| b'\n'))) | |
| ((Some(i)) (let ((line (.split_to buf i))) // remove the serialized frame from the buffer. | |
| (.split_to buf 1) // Also remove the '\n' | |
| (match ((:: str::from_utf8) (& line)) | |
| ((Ok(s)) (Ok (Some (.to_string s)))) | |
| ((Err(_)) (Err ((:: io::Error::new) ((:: io::ErrorKind::Other) .) "invalid UTF-8")))))) | |
| ((None) (Ok None))))) | |
| (defimpl (LineCodec: Encoder) | |
| (deftype Item String) | |
| (deftype Error io::Error) | |
| (defn encode (((self &mut Self) (msg String) (buf &mut BytesMut)) | |
| io::Result<()>) | |
| (.extend buf (.as_bytes msg)) | |
| (.extend buf b"\n") | |
| (Ok ()))) | |
| (defimpl <T> (LineProto: ServerProto<T>) | |
| (where (T AsyncRead) | |
| (T AsyncWrite) | |
| (T 'static)) | |
| // For this protocal style, `Request` matches the `Item` type of the codec's `Encoder` | |
| (deftype Request String) | |
| // `Response` matches the `Item` type of the codec's `Decoder` | |
| (deftype Response String) | |
| // boilerplate to hook in the codec | |
| (deftype Transport Framed<T, LineCodec>) | |
| (deftype BindTransport Result<Self::Transport, io::Error>) | |
| (defn bind_transport (((self &Self) (io T)) | |
| Self::BindTransport) | |
| (Ok (.framed io LineCodec)))) | |
| (defimpl (Echo: Service) | |
| // These types must match the corresponding protocol types; | |
| (deftype Request String) | |
| (deftype Response String) | |
| // For non-streaming protocols, service errors are always io::Error | |
| (deftype Error io::Error) | |
| // The future for computing the response; box it for simplicity. | |
| (deftype Future BoxFuture<Self::Response, Self::Error>) | |
| // Produce a future for computing a response from a request. | |
| (defn call (((self &Self) (req Self::Request)) | |
| Self::Future) | |
| // In this case, the response is immediate. | |
| (.boxed ((:: future::ok) req)))) | |
| (defn main (() ()) | |
| (let ((addr (.unwrap (.parse "0.0.0.0:12345"))) // Specify the localhost address | |
| (server ((:: TcpServer::new) LineProto addr))) // The builder requires a protocol and an address | |
| // We provide a way to *instantiate* the service for each new | |
| // connection; here, we just immediately return a new instance. | |
| (.serve server (lambda () | |
| (Ok Echo))))) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
