diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-01-13 11:26:42 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-01-13 11:26:42 +0100 |
| commit | a8f711d49ad65ee08c96fae2a8b52873667bdf5c (patch) | |
| tree | 7f54ec3421e0add1bbb143a1a2244dc9ba958480 /src/syntax/mod.rs | |
| parent | bd702c2029561a741f48095549a2b6ea97b3a09b (diff) | |
Checkpoint 🏁
Diffstat (limited to 'src/syntax/mod.rs')
| -rw-r--r-- | src/syntax/mod.rs | 311 |
1 files changed, 5 insertions, 306 deletions
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 10a509d2..11b35a06 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -6,312 +6,11 @@ use unicode_xid::UnicodeXID; use crate::func::LayoutFunc; use crate::size::{Size, ScaleSize}; + +pub type ParseResult<T> = crate::TypesetResult<T>; + +pub_use_mod!(color); +pub_use_mod!(expr); pub_use_mod!(tokens); pub_use_mod!(parsing); pub_use_mod!(span); - - -/// A tree representation of source code. -#[derive(Debug, PartialEq)] -pub struct SyntaxTree { - pub nodes: Vec<Spanned<Node>>, -} - -impl SyntaxTree { - /// Create an empty syntax tree. - pub fn new() -> SyntaxTree { - SyntaxTree { nodes: vec![] } - } -} - -/// A node in the syntax tree. -#[derive(Debug, PartialEq)] -pub enum Node { - /// Whitespace. - Space, - /// A line feed. - Newline, - /// Indicates that italics were toggled. - ToggleItalics, - /// Indicates that bolder text was toggled. - ToggleBolder, - /// Indicates that monospace was toggled. - ToggleMonospace, - /// Literal text. - Text(String), - /// A function invocation. - Func(FuncCall), -} - -/// A thing to be syntax highlighted. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum ColorToken { - Comment, - Bracket, - FuncName, - Colon, - KeyArg, - Equals, - Comma, - ExprNumber, - ExprSize, - ExprStr, - ExprIdent, - ExprBool, - Bold, - Italic, - Monospace, -} - -/// An invocation of a function. -#[derive(Debug)] -pub struct FuncCall(pub Box<dyn LayoutFunc>); - -impl PartialEq for FuncCall { - fn eq(&self, other: &FuncCall) -> bool { - &self.0 == &other.0 - } -} - -/// The arguments passed to a function. -#[derive(Debug, Clone, PartialEq)] -pub struct FuncArgs { - pub pos: Vec<Spanned<PosArg>>, - pub key: Vec<Spanned<KeyArg>>, -} - -impl FuncArgs { - /// Create an empty collection of arguments. - pub fn new() -> FuncArgs { - FuncArgs { - pos: vec![], - key: vec![], - } - } - - /// Add a positional argument. - pub fn add_pos(&mut self, arg: Spanned<PosArg>) { - self.pos.push(arg); - } - - /// Add a keyword argument. - pub fn add_key(&mut self, arg: Spanned<KeyArg>) { - self.key.push(arg); - } - - /// Force-extract the first positional argument. - pub fn get_pos<E: ExpressionKind>(&mut self) -> ParseResult<E> { - expect(self.get_pos_opt()) - } - - /// Extract the first positional argument. - pub fn get_pos_opt<E: ExpressionKind>(&mut self) -> ParseResult<Option<E>> { - Ok(if !self.pos.is_empty() { - let spanned = self.pos.remove(0); - Some(E::from_expr(spanned)?) - } else { - None - }) - } - - /// Iterator over positional arguments. - pub fn pos(&mut self) -> std::vec::IntoIter<Spanned<PosArg>> { - let vec = std::mem::replace(&mut self.pos, vec![]); - vec.into_iter() - } - - /// Force-extract a keyword argument. - pub fn get_key<E: ExpressionKind>(&mut self, name: &str) -> ParseResult<E> { - expect(self.get_key_opt(name)) - } - - /// Extract a keyword argument. - pub fn get_key_opt<E: ExpressionKind>(&mut self, name: &str) -> ParseResult<Option<E>> { - Ok(if let Some(index) = self.key.iter().position(|arg| arg.v.key.v.0 == name) { - let value = self.key.swap_remove(index).v.value; - Some(E::from_expr(value)?) - } else { - None - }) - } - - /// Extract any keyword argument. - pub fn get_key_next(&mut self) -> Option<Spanned<KeyArg>> { - self.key.pop() - } - - /// Iterator over all keyword arguments. - pub fn keys(&mut self) -> std::vec::IntoIter<Spanned<KeyArg>> { - let vec = std::mem::replace(&mut self.key, vec![]); - vec.into_iter() - } - - /// Clear the argument lists. - pub fn clear(&mut self) { - self.pos.clear(); - self.key.clear(); - } - - /// Whether both the positional and keyword argument lists are empty. - pub fn is_empty(&self) -> bool { - self.pos.is_empty() && self.key.is_empty() - } -} - -/// Extract the option expression kind from the option or return an error. -fn expect<E: ExpressionKind>(opt: ParseResult<Option<E>>) -> ParseResult<E> { - match opt { - Ok(Some(spanned)) => Ok(spanned), - Ok(None) => error!("expected {}", E::NAME), - Err(e) => Err(e), - } -} - -/// A positional argument passed to a function. -pub type PosArg = Expression; - -/// A keyword argument passed to a function. -#[derive(Debug, Clone, PartialEq)] -pub struct KeyArg { - pub key: Spanned<Ident>, - pub value: Spanned<Expression>, -} - -/// Either a positional or keyword argument. -#[derive(Debug, Clone, PartialEq)] -pub enum DynArg { - Pos(Spanned<PosArg>), - Key(Spanned<KeyArg>), -} - -/// An argument or return value. -#[derive(Clone, PartialEq)] -pub enum Expression { - Ident(Ident), - Str(String), - Num(f64), - Size(Size), - Bool(bool), -} - -impl Display for Expression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use Expression::*; - match self { - Ident(i) => write!(f, "{}", i), - Str(s) => write!(f, "{:?}", s), - Num(n) => write!(f, "{}", n), - Size(s) => write!(f, "{}", s), - Bool(b) => write!(f, "{}", b), - } - } -} - -debug_display!(Expression); - -/// An identifier. -#[derive(Clone, PartialEq)] -pub struct Ident(pub String); - -impl Ident { - pub fn new<S>(ident: S) -> Option<Ident> where S: AsRef<str> + Into<String> { - if is_identifier(ident.as_ref()) { - Some(Ident(ident.into())) - } else { - None - } - } - - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} - -impl Display for Ident { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -debug_display!(Ident); - -/// Whether this word is a valid identifier. -fn is_identifier(string: &str) -> bool { - let mut chars = string.chars(); - - match chars.next() { - Some('-') => {} - Some(c) if UnicodeXID::is_xid_start(c) => {} - _ => return false, - } - - while let Some(c) = chars.next() { - match c { - '.' | '-' => {} - c if UnicodeXID::is_xid_continue(c) => {} - _ => return false, - } - } - - true -} - -/// Kinds of expressions. -pub trait ExpressionKind: Sized { - const NAME: &'static str; - - /// Create from expression. - fn from_expr(expr: Spanned<Expression>) -> ParseResult<Self>; -} - -macro_rules! kind { - ($type:ty, $name:expr, $($patterns:tt)*) => { - impl ExpressionKind for $type { - const NAME: &'static str = $name; - - fn from_expr(expr: Spanned<Expression>) -> ParseResult<Self> { - #[allow(unreachable_patterns)] - Ok(match expr.v { - $($patterns)*, - _ => error!("expected {}", Self::NAME), - }) - } - } - }; -} - -kind!(Expression, "expression", e => e); -kind!(Ident, "identifier", Expression::Ident(ident) => ident); -kind!(String, "string", Expression::Str(string) => string); -kind!(f64, "number", Expression::Num(num) => num); -kind!(bool, "boolean", Expression::Bool(boolean) => boolean); -kind!(Size, "size", Expression::Size(size) => size); -kind!(ScaleSize, "number or size", - Expression::Size(size) => ScaleSize::Absolute(size), - Expression::Num(scale) => ScaleSize::Scaled(scale as f32) -); - -impl<T> ExpressionKind for Spanned<T> where T: ExpressionKind { - const NAME: &'static str = T::NAME; - - fn from_expr(expr: Spanned<Expression>) -> ParseResult<Spanned<T>> { - let span = expr.span; - T::from_expr(expr) - .map(|v| Spanned::new(v, span)) - } -} - -impl<T> ExpressionKind for Option<T> where T: ExpressionKind { - const NAME: &'static str = T::NAME; - - fn from_expr(expr: Spanned<Expression>) -> ParseResult<Option<T>> { - if let Expression::Ident(ident) = &expr.v { - match ident.as_str() { - "default" | "none" => return Ok(None), - _ => {}, - } - } - - T::from_expr(expr).map(|v| Some(v)) - } -} |
