conlang: Add unconditional loop expression, for desugaring
This commit is contained in:
		@@ -367,6 +367,7 @@ mod display {
 | 
			
		||||
                ExprKind::Empty => "()".fmt(f),
 | 
			
		||||
                ExprKind::Group(v) => v.fmt(f),
 | 
			
		||||
                ExprKind::Tuple(v) => v.fmt(f),
 | 
			
		||||
                ExprKind::Loop(v) => v.fmt(f),
 | 
			
		||||
                ExprKind::While(v) => v.fmt(f),
 | 
			
		||||
                ExprKind::If(v) => v.fmt(f),
 | 
			
		||||
                ExprKind::For(v) => v.fmt(f),
 | 
			
		||||
@@ -534,6 +535,12 @@ mod display {
 | 
			
		||||
            write!(f, "({})", self.expr)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    impl Display for Loop {
 | 
			
		||||
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
            let Self { body } = self;
 | 
			
		||||
            write!(f, "loop {body}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    impl Display for While {
 | 
			
		||||
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
            let Self { cond, pass, fail } = self;
 | 
			
		||||
 
 | 
			
		||||
@@ -346,6 +346,8 @@ pub enum ExprKind {
 | 
			
		||||
    Group(Group),
 | 
			
		||||
    /// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
 | 
			
		||||
    Tuple(Tuple),
 | 
			
		||||
    /// A [Loop] expression: `loop` [`Block`]
 | 
			
		||||
    Loop(Loop),
 | 
			
		||||
    /// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
 | 
			
		||||
    While(While),
 | 
			
		||||
    /// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]?
 | 
			
		||||
@@ -492,6 +494,12 @@ pub struct Tuple {
 | 
			
		||||
    pub exprs: Vec<Expr>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A [Loop] expression: `loop` [`Block`]
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct Loop {
 | 
			
		||||
    pub body: Block,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct While {
 | 
			
		||||
 
 | 
			
		||||
@@ -131,6 +131,7 @@ impl Interpret for ExprKind {
 | 
			
		||||
            ExprKind::Empty => Ok(ConValue::Empty),
 | 
			
		||||
            ExprKind::Group(v) => v.interpret(env),
 | 
			
		||||
            ExprKind::Tuple(v) => v.interpret(env),
 | 
			
		||||
            ExprKind::Loop(v) => v.interpret(env),
 | 
			
		||||
            ExprKind::While(v) => v.interpret(env),
 | 
			
		||||
            ExprKind::If(v) => v.interpret(env),
 | 
			
		||||
            ExprKind::For(v) => v.interpret(env),
 | 
			
		||||
@@ -365,17 +366,32 @@ impl Interpret for Tuple {
 | 
			
		||||
        )?))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Interpret for While {
 | 
			
		||||
impl Interpret for Loop {
 | 
			
		||||
    fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
 | 
			
		||||
        let Self { cond, pass, fail } = self;
 | 
			
		||||
        while cond.interpret(env)?.truthy()? {
 | 
			
		||||
            match pass.interpret(env) {
 | 
			
		||||
        let Self { body } = self;
 | 
			
		||||
        loop {
 | 
			
		||||
            match body.interpret(env) {
 | 
			
		||||
                Err(Error::Break(value)) => return Ok(value),
 | 
			
		||||
                Err(Error::Continue) => continue,
 | 
			
		||||
                e => e?,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        fail.interpret(env)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Interpret for While {
 | 
			
		||||
    fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
 | 
			
		||||
        let Self { cond, pass, fail } = self;
 | 
			
		||||
        loop {
 | 
			
		||||
            if cond.interpret(env)?.truthy()? {
 | 
			
		||||
                match pass.interpret(env) {
 | 
			
		||||
                    Err(Error::Break(value)) => return Ok(value),
 | 
			
		||||
                    Err(Error::Continue) => continue,
 | 
			
		||||
                    e => e?,
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                break fail.interpret(env);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Interpret for If {
 | 
			
		||||
@@ -392,23 +408,24 @@ impl Interpret for For {
 | 
			
		||||
    fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
 | 
			
		||||
        let Self { bind: Identifier(name), cond, pass, fail } = self;
 | 
			
		||||
        // TODO: A better iterator model
 | 
			
		||||
        let bounds = match cond.interpret(env)? {
 | 
			
		||||
        let mut bounds = match cond.interpret(env)? {
 | 
			
		||||
            ConValue::RangeExc(a, b) => a..=b,
 | 
			
		||||
            ConValue::RangeInc(a, b) => a..=b,
 | 
			
		||||
            _ => Err(Error::TypeError)?,
 | 
			
		||||
        };
 | 
			
		||||
        {
 | 
			
		||||
        loop {
 | 
			
		||||
            let mut env = env.frame("loop variable");
 | 
			
		||||
            for loop_var in bounds {
 | 
			
		||||
            if let Some(loop_var) = bounds.next() {
 | 
			
		||||
                env.insert(name, Some(loop_var.into()));
 | 
			
		||||
                match pass.interpret(&mut env) {
 | 
			
		||||
                    Err(Error::Break(value)) => return Ok(value),
 | 
			
		||||
                    Err(Error::Continue) => continue,
 | 
			
		||||
                    result => result?,
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                break fail.interpret(&mut env);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fail.interpret(env)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Interpret for Else {
 | 
			
		||||
 
 | 
			
		||||
@@ -103,6 +103,7 @@ pub enum Parsing {
 | 
			
		||||
    Block,
 | 
			
		||||
    Group,
 | 
			
		||||
    Tuple,
 | 
			
		||||
    Loop,
 | 
			
		||||
    While,
 | 
			
		||||
    If,
 | 
			
		||||
    For,
 | 
			
		||||
@@ -204,6 +205,7 @@ impl Display for Parsing {
 | 
			
		||||
            Parsing::Block => "a block",
 | 
			
		||||
            Parsing::Group => "a grouped expression",
 | 
			
		||||
            Parsing::Tuple => "a tuple",
 | 
			
		||||
            Parsing::Loop => "an unconditional loop expression",
 | 
			
		||||
            Parsing::While => "a while expression",
 | 
			
		||||
            Parsing::If => "an if expression",
 | 
			
		||||
            Parsing::For => "a for expression",
 | 
			
		||||
 
 | 
			
		||||
@@ -809,6 +809,7 @@ impl<'t> Parser<'t> {
 | 
			
		||||
                self.consume_peeked();
 | 
			
		||||
                Unary { kind, tail: self.exprkind(after)?.into() }.into()
 | 
			
		||||
            }
 | 
			
		||||
            TokenKind::Loop => ExprKind::Loop(self.parse_loop()?),
 | 
			
		||||
            TokenKind::While => ExprKind::While(self.parse_while()?),
 | 
			
		||||
            TokenKind::If => ExprKind::If(self.parse_if()?),
 | 
			
		||||
            TokenKind::For => ExprKind::For(self.parse_for()?),
 | 
			
		||||
@@ -1010,6 +1011,12 @@ impl<'t> Parser<'t> {
 | 
			
		||||
}
 | 
			
		||||
/// ## Control flow subexpressions
 | 
			
		||||
impl<'t> Parser<'t> {
 | 
			
		||||
    /// [Loop] = `loop` [Block]
 | 
			
		||||
    pub fn parse_loop(&mut self) -> PResult<Loop> {
 | 
			
		||||
        self.match_type(TokenKind::Loop, Parsing::Loop)?;
 | 
			
		||||
        Ok(Loop { body: self.block()? })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// [While] = `while` [Expr] [Block] [Else]?
 | 
			
		||||
    pub fn parse_while(&mut self) -> PResult<While> {
 | 
			
		||||
        self.match_type(TokenKind::While, Parsing::While)?;
 | 
			
		||||
 
 | 
			
		||||
@@ -383,6 +383,7 @@ pub mod yamlify {
 | 
			
		||||
                ExprKind::Empty => {}
 | 
			
		||||
                ExprKind::Group(k) => k.yaml(y),
 | 
			
		||||
                ExprKind::Tuple(k) => k.yaml(y),
 | 
			
		||||
                ExprKind::Loop(k) => k.yaml(y),
 | 
			
		||||
                ExprKind::While(k) => k.yaml(y),
 | 
			
		||||
                ExprKind::If(k) => k.yaml(y),
 | 
			
		||||
                ExprKind::For(k) => k.yaml(y),
 | 
			
		||||
@@ -472,6 +473,12 @@ pub mod yamlify {
 | 
			
		||||
            y.key("Group").yaml(expr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    impl Yamlify for Loop {
 | 
			
		||||
        fn yaml(&self, y: &mut Yamler) {
 | 
			
		||||
            let Self { body } = self;
 | 
			
		||||
            y.key("Loop").yaml(body);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    impl Yamlify for While {
 | 
			
		||||
        fn yaml(&self, y: &mut Yamler) {
 | 
			
		||||
            let Self { cond, pass, fail } = self;
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ pub enum TokenKind {
 | 
			
		||||
    Impl,
 | 
			
		||||
    In,
 | 
			
		||||
    Let,
 | 
			
		||||
    Loop,
 | 
			
		||||
    Mod,
 | 
			
		||||
    Mut,
 | 
			
		||||
    Pub,
 | 
			
		||||
@@ -122,6 +123,7 @@ impl Display for TokenKind {
 | 
			
		||||
            TokenKind::Impl => "impl".fmt(f),
 | 
			
		||||
            TokenKind::In => "in".fmt(f),
 | 
			
		||||
            TokenKind::Let => "let".fmt(f),
 | 
			
		||||
            TokenKind::Loop => "loop".fmt(f),
 | 
			
		||||
            TokenKind::Mod => "mod".fmt(f),
 | 
			
		||||
            TokenKind::Mut => "mut".fmt(f),
 | 
			
		||||
            TokenKind::Pub => "pub".fmt(f),
 | 
			
		||||
@@ -158,6 +160,7 @@ impl FromStr for TokenKind {
 | 
			
		||||
            "impl" => Self::Impl,
 | 
			
		||||
            "in" => Self::In,
 | 
			
		||||
            "let" => Self::Let,
 | 
			
		||||
            "loop" => Self::Loop,
 | 
			
		||||
            "mod" => Self::Mod,
 | 
			
		||||
            "mut" => Self::Mut,
 | 
			
		||||
            "pub" => Self::Pub,
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ Index       = Primary ('[' Indices ']')* ;
 | 
			
		||||
Indices     = (Expr ',')* Expr? ;
 | 
			
		||||
 | 
			
		||||
Primary     = Literal | Path  | Array | ArrayRep | AddrOf 
 | 
			
		||||
            | Block   | Group 
 | 
			
		||||
            | Block   | Group | Loop
 | 
			
		||||
            | If      | While | For   | Break    | Return | Continue;
 | 
			
		||||
 | 
			
		||||
Literal     = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
 | 
			
		||||
@@ -114,6 +114,7 @@ Block       = '{' Stmt* '}';
 | 
			
		||||
Group       = Empty | '(' (Expr | Tuple) ')' ;
 | 
			
		||||
Tuple       = (Expr ',')* Expr? ;
 | 
			
		||||
 | 
			
		||||
Loop        = "loop"  Block ;
 | 
			
		||||
While       = "while" Expr Block Else ;
 | 
			
		||||
If          = "if"    Expr Block Else ;
 | 
			
		||||
For         = "for"   Identifier "in" Expr Block Else ;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user