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