Add control flow types
This commit is contained in:
parent
76f7524fdb
commit
cd1bb91555
@ -54,6 +54,14 @@ pub enum StatementKind {
|
|||||||
Declaration(Declaration),
|
Declaration(Declaration),
|
||||||
Import(ImportSpecifier),
|
Import(ImportSpecifier),
|
||||||
Module(ModuleSpecifier),
|
Module(ModuleSpecifier),
|
||||||
|
Flow(FlowControl),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum FlowControl {
|
||||||
|
Continue,
|
||||||
|
Break,
|
||||||
|
Return(Option<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
@ -47,6 +47,9 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
|
|||||||
if let Recursion::Continue = v.module(module_spec) {
|
if let Recursion::Continue = v.module(module_spec) {
|
||||||
walk_block(v, &module_spec.contents);
|
walk_block(v, &module_spec.contents);
|
||||||
},
|
},
|
||||||
|
Flow(ref _flow_control) => {
|
||||||
|
//TODO do something with flow control in Visitor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#![allow(clippy::single_char_add_str)]
|
#![allow(clippy::single_char_add_str)]
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Block, Declaration, Expression, ExpressionKind, ImportSpecifier, InvocationArgument, ModuleSpecifier,
|
Block, Declaration, Expression, ExpressionKind, FlowControl, ImportSpecifier, InvocationArgument,
|
||||||
Signature, Statement, StatementKind, AST,
|
ModuleSpecifier, Signature, Statement, StatementKind, AST,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LEVEL: usize = 2;
|
const LEVEL: usize = 2;
|
||||||
@ -35,6 +37,7 @@ fn render_statement(stmt: &Statement, indent: usize, buf: &mut String) {
|
|||||||
Declaration(ref decl) => render_declaration(decl, indent, buf),
|
Declaration(ref decl) => render_declaration(decl, indent, buf),
|
||||||
Import(ref spec) => render_import(spec, indent, buf),
|
Import(ref spec) => render_import(spec, indent, buf),
|
||||||
Module(ref spec) => render_module(spec, indent, buf),
|
Module(ref spec) => render_module(spec, indent, buf),
|
||||||
|
Flow(ref flow_control) => render_flow_control(flow_control, indent, buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +194,15 @@ fn render_module(_expr: &ModuleSpecifier, _indent: usize, buf: &mut String) {
|
|||||||
buf.push_str("(Module <some mod>)");
|
buf.push_str("(Module <some mod>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_flow_control(flow: &FlowControl, _indent: usize, buf: &mut String) {
|
||||||
|
use FlowControl::*;
|
||||||
|
match flow {
|
||||||
|
Return(ref _expr) => write!(buf, "return <expr>").unwrap(),
|
||||||
|
Break => write!(buf, "break").unwrap(),
|
||||||
|
Continue => write!(buf, "continue").unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::render_ast;
|
use super::render_ast;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
//! ```text
|
//! ```text
|
||||||
//! program := (statement delimiter)* EOF
|
//! program := (statement delimiter)* EOF
|
||||||
//! delimiter := NEWLINE | ";"
|
//! delimiter := NEWLINE | ";"
|
||||||
//! statement := expression | declaration | import | module
|
//! statement := expression | declaration | import | module | flow
|
||||||
//! block := "{" (statement delimiter)* "}"
|
//! block := "{" (statement delimiter)* "}"
|
||||||
//! declaration := type_declaration | func_declaration | binding_declaration | impl_declaration
|
//! declaration := type_declaration | func_declaration | binding_declaration | impl_declaration
|
||||||
//! ```
|
//! ```
|
||||||
@ -401,12 +401,28 @@ impl Parser {
|
|||||||
Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration),
|
Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration),
|
||||||
Keyword(Import) => self.import_declaration().map(StatementKind::Import),
|
Keyword(Import) => self.import_declaration().map(StatementKind::Import),
|
||||||
Keyword(Module) => self.module_declaration().map(StatementKind::Module),
|
Keyword(Module) => self.module_declaration().map(StatementKind::Module),
|
||||||
|
Keyword(Continue) | Keyword(Return) | Keyword(Break) =>
|
||||||
|
self.flow_control().map(StatementKind::Flow),
|
||||||
_ => self.expression().map(StatementKind::Expression),
|
_ => self.expression().map(StatementKind::Expression),
|
||||||
}?;
|
}?;
|
||||||
let id = self.id_store.fresh();
|
let id = self.id_store.fresh();
|
||||||
Ok(Statement { kind, id, location: tok.location })
|
Ok(Statement { kind, id, location: tok.location })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[recursive_descent_method]
|
||||||
|
fn flow_control(&mut self) -> ParseResult<FlowControl> {
|
||||||
|
let tok = self.token_handler.next();
|
||||||
|
Ok(match tok.get_kind() {
|
||||||
|
Keyword(Continue) => FlowControl::Continue,
|
||||||
|
Keyword(Break) => FlowControl::Break,
|
||||||
|
Keyword(Return) => match self.token_handler.peek_kind() {
|
||||||
|
Semicolon | Newline => FlowControl::Return(None),
|
||||||
|
_ => FlowControl::Return(Some(self.expression()?)),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
fn annotation(&mut self) -> ParseResult<Declaration> {
|
fn annotation(&mut self) -> ParseResult<Declaration> {
|
||||||
expect!(self, AtSign);
|
expect!(self, AtSign);
|
||||||
|
@ -1215,3 +1215,38 @@ if (45, "panda", false, 2.2) {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flow_control() {
|
||||||
|
use ExpressionKind::*;
|
||||||
|
|
||||||
|
// This is an incorrect program, but shoudl parse correctly.
|
||||||
|
let source = r#"
|
||||||
|
fn test() {
|
||||||
|
let a = 10;
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
return;
|
||||||
|
return 10;
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
assert_ast!(
|
||||||
|
source,
|
||||||
|
vec![fn_decl(
|
||||||
|
Signature { name: rc("test"), operator: false, type_anno: None, params: vec![] },
|
||||||
|
vec![
|
||||||
|
decl(Declaration::Binding {
|
||||||
|
name: rc("a"),
|
||||||
|
constant: true,
|
||||||
|
type_anno: None,
|
||||||
|
expr: expr(NatLiteral(10))
|
||||||
|
}),
|
||||||
|
stmt(StatementKind::Flow(FlowControl::Break)),
|
||||||
|
stmt(StatementKind::Flow(FlowControl::Continue)),
|
||||||
|
stmt(StatementKind::Flow(FlowControl::Return(None))),
|
||||||
|
stmt(StatementKind::Flow(FlowControl::Return(Some(expr(NatLiteral(10)))))),
|
||||||
|
]
|
||||||
|
.into()
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -80,6 +80,9 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
ast::StatementKind::Module(_modspec) => {
|
ast::StatementKind::Module(_modspec) => {
|
||||||
//TODO handle modules
|
//TODO handle modules
|
||||||
}
|
}
|
||||||
|
ast::StatementKind::Flow(..) => {
|
||||||
|
//TODO this should be an error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +103,18 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
_ => None,
|
ast::StatementKind::Module(_) | ast::StatementKind::Import(_) => {
|
||||||
|
//TODO need to handle function-internal modules, imports
|
||||||
|
None
|
||||||
|
}
|
||||||
|
ast::StatementKind::Flow(ast::FlowControl::Return(expr)) =>
|
||||||
|
if let Some(expr) = expr {
|
||||||
|
Some(Statement::Return(self.expression(expr)))
|
||||||
|
} else {
|
||||||
|
Some(Statement::Return(Expression::unit()))
|
||||||
|
},
|
||||||
|
ast::StatementKind::Flow(ast::FlowControl::Break) => Some(Statement::Break),
|
||||||
|
ast::StatementKind::Flow(ast::FlowControl::Continue) => Some(Statement::Continue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,9 @@ impl ReducedIR {
|
|||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
Binding { id: DefId, constant: bool, expr: Expression },
|
Binding { id: DefId, constant: bool, expr: Expression },
|
||||||
|
Return(Expression),
|
||||||
|
Continue,
|
||||||
|
Break,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -86,11 +86,12 @@ pub enum Kw {
|
|||||||
Func,
|
Func,
|
||||||
For,
|
For,
|
||||||
While,
|
While,
|
||||||
Const,
|
|
||||||
Let,
|
Let,
|
||||||
In,
|
In,
|
||||||
Mut,
|
Mut,
|
||||||
Return,
|
Return,
|
||||||
|
Continue,
|
||||||
|
Break,
|
||||||
Alias,
|
Alias,
|
||||||
Type,
|
Type,
|
||||||
SelfType,
|
SelfType,
|
||||||
@ -115,11 +116,12 @@ impl TryFrom<&str> for Kw {
|
|||||||
"fn" => Kw::Func,
|
"fn" => Kw::Func,
|
||||||
"for" => Kw::For,
|
"for" => Kw::For,
|
||||||
"while" => Kw::While,
|
"while" => Kw::While,
|
||||||
"const" => Kw::Const,
|
|
||||||
"let" => Kw::Let,
|
"let" => Kw::Let,
|
||||||
"in" => Kw::In,
|
"in" => Kw::In,
|
||||||
"mut" => Kw::Mut,
|
"mut" => Kw::Mut,
|
||||||
"return" => Kw::Return,
|
"return" => Kw::Return,
|
||||||
|
"break" => Kw::Break,
|
||||||
|
"continue" => Kw::Continue,
|
||||||
"alias" => Kw::Alias,
|
"alias" => Kw::Alias,
|
||||||
"type" => Kw::Type,
|
"type" => Kw::Type,
|
||||||
"Self" => Kw::SelfType,
|
"Self" => Kw::SelfType,
|
||||||
|
@ -58,6 +58,9 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
let evaluated = self.expression(expr)?;
|
let evaluated = self.expression(expr)?;
|
||||||
Ok(Some(evaluated.into()))
|
Ok(Some(evaluated.into()))
|
||||||
}
|
}
|
||||||
|
Statement::Return(expr) => unimplemented!(),
|
||||||
|
Statement::Break => unimplemented!(),
|
||||||
|
Statement::Continue => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user