Skip to content

Commit

Permalink
Expand quote! to allow for using all tokens and literals
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Sep 8, 2020
1 parent 0fe9ee6 commit 12224a4
Show file tree
Hide file tree
Showing 23 changed files with 1,048 additions and 329 deletions.
2 changes: 1 addition & 1 deletion crates/rune-macros/src/lib.rs
Expand Up @@ -71,7 +71,7 @@ fn make_function(ctx: &mut MacroContext, stream: &TokenStream) -> runestick::Res
Ok(rune::quote!(ctx => fn #ident() { #output }))
}

/// Construct the `http` module.
/// Construct the `experimental macros` module.
pub fn module() -> Result<runestick::Module, runestick::ContextError> {
let mut module = runestick::Module::new(&["std", "experiments"]);
module.macro_(&["passthrough"], passthrough_impl)?;
Expand Down
8 changes: 4 additions & 4 deletions crates/rune/src/ast/expr.rs
Expand Up @@ -348,7 +348,7 @@ impl Expr {
ast::Kind::Self_ => Self::Self_(parser.parse()?),
ast::Kind::Select => Self::ExprSelect(parser.parse()?),
ast::Kind::PipePipe | ast::Kind::Pipe => Self::ExprClosure(parser.parse()?),
ast::Kind::Label => {
ast::Kind::Label(..) => {
let label = Some((parser.parse::<ast::Label>()?, parser.parse::<ast::Colon>()?));
let token = parser.token_peek_eof()?;

Expand All @@ -368,7 +368,7 @@ impl Expr {
}
});
}
ast::Kind::Hash => Self::LitObject(parser.parse()?),
ast::Kind::Pound => Self::LitObject(parser.parse()?),
ast::Kind::Bang | ast::Kind::Amp | ast::Kind::Star => Self::ExprUnary(parser.parse()?),
ast::Kind::While => Self::ExprWhile(parser.parse()?),
ast::Kind::Loop => Self::ExprLoop(parser.parse()?),
Expand Down Expand Up @@ -608,8 +608,8 @@ impl Peek for Expr {
ast::Kind::Async => true,
ast::Kind::Self_ => true,
ast::Kind::Select => true,
ast::Kind::Label => matches!(t2.map(|t| t.kind), Some(ast::Kind::Colon)),
ast::Kind::Hash => true,
ast::Kind::Label(..) => matches!(t2.map(|t| t.kind), Some(ast::Kind::Colon)),
ast::Kind::Pound => true,
ast::Kind::Bang | ast::Kind::Amp | ast::Kind::Star => true,
ast::Kind::While => true,
ast::Kind::Loop => true,
Expand Down
7 changes: 3 additions & 4 deletions crates/rune/src/ast/expr_break.rs
@@ -1,5 +1,4 @@
use crate::ast;
use crate::ast::{Kind, Token};
use crate::error::ParseError;
use crate::parser::Parser;
use crate::traits::{Parse, Peek};
Expand Down Expand Up @@ -62,16 +61,16 @@ impl Parse for ExprBreakValue {
let token = parser.token_peek_eof()?;

Ok(match token.kind {
ast::Kind::Label => Self::Label(parser.parse()?),
ast::Kind::Label(..) => Self::Label(parser.parse()?),
_ => Self::Expr(Box::new(parser.parse()?)),
})
}
}

impl Peek for ExprBreakValue {
fn peek(t1: Option<Token>, t2: Option<Token>) -> bool {
fn peek(t1: Option<ast::Token>, t2: Option<ast::Token>) -> bool {
match t1.map(|t| t.kind) {
Some(Kind::Label) => true,
Some(ast::Kind::Label(..)) => true,
_ => ast::Expr::peek(t1, t2),
}
}
Expand Down
18 changes: 11 additions & 7 deletions crates/rune/src/ast/ident.rs
Expand Up @@ -9,7 +9,7 @@ pub struct Ident {
/// The kind of the identifier.
pub token: ast::Token,
/// The kind of the identifier.
pub kind: ast::IdentKind,
pub kind: ast::StringSource,
}

impl Ident {
Expand All @@ -26,7 +26,7 @@ impl Parse for Ident {
match token.kind {
ast::Kind::Ident(kind) => Ok(Self { token, kind }),
_ => Err(ParseError::TokenMismatch {
expected: ast::Kind::Ident(ast::IdentKind::Source),
expected: ast::Kind::Ident(ast::StringSource::Text),
actual: token.kind,
span: token.span,
}),
Expand All @@ -50,19 +50,23 @@ impl<'a> Resolve<'a> for Ident {
let span = self.token.span;

match self.kind {
ast::IdentKind::Source => {
ast::StringSource::Text => {
let ident = source
.source(span)
.ok_or_else(|| ParseError::BadSlice { span })?;

Ok(Cow::Borrowed(ident))
}
ast::IdentKind::Synthetic(id) => {
ast::StringSource::Synthetic(id) => {
let ident = storage
.get_ident(id)
.ok_or_else(|| ParseError::BadIdentId { id, span })?;
.get_string(id)
.ok_or_else(|| ParseError::BadSyntheticId {
kind: "label",
id,
span,
})?;

Ok(Cow::Owned(ident))
Ok(Cow::Owned(ident.to_owned()))
}
}
}
Expand Down
81 changes: 81 additions & 0 deletions crates/rune/src/ast/label.rs
@@ -0,0 +1,81 @@
use crate::ast;
use crate::{Parse, ParseError, Parser, Peek, Resolve, Storage};
use runestick::{Source, Span};
use std::borrow::Cow;

/// A label, like `'foo`
#[derive(Debug, Clone, Copy)]
pub struct Label {
/// The token of the label.
pub token: ast::Token,
/// The kind of the label.
pub kind: ast::StringSource,
}

impl Label {
/// Access the span of the identifier.
pub fn span(&self) -> Span {
self.token.span
}
}

impl Parse for Label {
fn parse(parser: &mut Parser<'_>) -> Result<Self, ParseError> {
let token = parser.token_next()?;

match token.kind {
ast::Kind::Label(kind) => Ok(Self { token, kind }),
_ => Err(ParseError::TokenMismatch {
expected: ast::Kind::Label(ast::StringSource::Text),
actual: token.kind,
span: token.span,
}),
}
}
}

impl Peek for Label {
fn peek(p1: Option<ast::Token>, _: Option<ast::Token>) -> bool {
match p1 {
Some(p1) => matches!(p1.kind, ast::Kind::Label(..)),
_ => false,
}
}
}

impl<'a> Resolve<'a> for Label {
type Output = Cow<'a, str>;

fn resolve(&self, storage: &Storage, source: &'a Source) -> Result<Cow<'a, str>, ParseError> {
let span = self.token.span;

match self.kind {
ast::StringSource::Text => {
let span = self.token.span;

let ident = source
.source(span.trim_start(1))
.ok_or_else(|| ParseError::BadSlice { span })?;

Ok(Cow::Borrowed(ident))
}
ast::StringSource::Synthetic(id) => {
let ident = storage
.get_string(id)
.ok_or_else(|| ParseError::BadSyntheticId {
kind: "ident",
id,
span,
})?;

Ok(Cow::Owned(ident.to_owned()))
}
}
}
}

impl crate::IntoTokens for Label {
fn into_tokens(&self, _: &mut crate::MacroContext, stream: &mut crate::TokenStream) {
stream.push(self.token);
}
}
9 changes: 8 additions & 1 deletion crates/rune/src/ast/lit_byte.rs
Expand Up @@ -7,6 +7,8 @@ use runestick::{Source, Span};
pub struct LitByte {
/// The token corresponding to the literal.
pub token: ast::Token,
/// The source of the byte.
pub source: ast::CopySource<u8>,
}

impl LitByte {
Expand Down Expand Up @@ -34,7 +36,7 @@ impl Parse for LitByte {
let token = parser.token_next()?;

Ok(match token.kind {
ast::Kind::LitByte => LitByte { token },
ast::Kind::LitByte(source) => LitByte { token, source },
_ => {
return Err(ParseError::ExpectedByte {
actual: token.kind,
Expand All @@ -49,6 +51,11 @@ impl<'a> Resolve<'a> for LitByte {
type Output = u8;

fn resolve(&self, _: &Storage, source: &'a Source) -> Result<u8, ParseError> {
match self.source {
ast::CopySource::Inline(b) => return Ok(b),
ast::CopySource::Text => (),
}

let span = self.token.span;

let string = source
Expand Down
28 changes: 23 additions & 5 deletions crates/rune/src/ast/lit_byte_str.rs
Expand Up @@ -9,7 +9,7 @@ pub struct LitByteStr {
/// The token corresponding to the literal.
token: ast::Token,
/// If the string literal is escaped.
escaped: bool,
source: ast::LitByteStrSource,
}

impl LitByteStr {
Expand Down Expand Up @@ -42,13 +42,31 @@ impl LitByteStr {
impl<'a> Resolve<'a> for LitByteStr {
type Output = Cow<'a, [u8]>;

fn resolve(&self, _: &Storage, source: &'a Source) -> Result<Cow<'a, [u8]>, ParseError> {
let span = self.token.span.trim_start(2).trim_end(1);
fn resolve(&self, storage: &Storage, source: &'a Source) -> Result<Cow<'a, [u8]>, ParseError> {
let span = self.token.span;

let text = match self.source {
ast::LitByteStrSource::Text(text) => text,
ast::LitByteStrSource::Synthetic(id) => {
let bytes =
storage
.get_byte_string(id)
.ok_or_else(|| ParseError::BadSyntheticId {
kind: "byte string",
id,
span,
})?;

return Ok(Cow::Owned(bytes));
}
};

let span = span.trim_start(2).trim_end(1);
let string = source
.source(span)
.ok_or_else(|| ParseError::BadSlice { span })?;

Ok(if self.escaped {
Ok(if text.escaped {
Cow::Owned(self.parse_escaped(span, string)?)
} else {
Cow::Borrowed(string.as_bytes())
Expand All @@ -71,7 +89,7 @@ impl Parse for LitByteStr {
let token = parser.token_next()?;

match token.kind {
ast::Kind::LitByteStr { escaped } => Ok(Self { token, escaped }),
ast::Kind::LitByteStr(source) => Ok(Self { token, source }),
_ => Err(ParseError::ExpectedString {
actual: token.kind,
span: token.span,
Expand Down
9 changes: 8 additions & 1 deletion crates/rune/src/ast/lit_char.rs
Expand Up @@ -7,6 +7,8 @@ use runestick::{Source, Span};
pub struct LitChar {
/// The token corresponding to the literal.
pub token: ast::Token,
/// The source of the literal character.
pub source: ast::CopySource<char>,
}

impl LitChar {
Expand Down Expand Up @@ -34,7 +36,7 @@ impl Parse for LitChar {
let token = parser.token_next()?;

Ok(match token.kind {
ast::Kind::LitChar => LitChar { token },
ast::Kind::LitChar(source) => LitChar { token, source },
_ => {
return Err(ParseError::ExpectedChar {
actual: token.kind,
Expand All @@ -49,6 +51,11 @@ impl<'a> Resolve<'a> for LitChar {
type Output = char;

fn resolve(&self, _: &Storage, source: &'a Source) -> Result<char, ParseError> {
match self.source {
ast::CopySource::Inline(c) => return Ok(c),
ast::CopySource::Text => (),
}

let span = self.token.span;
let string = source
.source(span.narrow(1))
Expand Down

0 comments on commit 12224a4

Please sign in to comment.