add match blocks and constant literals
This commit is contained in:
parent
68be74d032
commit
da5258a11a
113
src/frontend.rs
113
src/frontend.rs
|
@ -3,6 +3,7 @@ use std::collections::BTreeMap;
|
|||
use std::fmt::Write;
|
||||
|
||||
use super::parser;
|
||||
use super::parser::block_expression::BlockExpr;
|
||||
use crate::rtlil;
|
||||
pub use callable::{Callable, CallableContext, CallableId};
|
||||
pub use types::{Type, TypeStruct, TypingContext};
|
||||
|
@ -119,11 +120,8 @@ impl Context {
|
|||
match &expr.kind {
|
||||
typed_ir::ExprKind::Literal(lit) => Ok(lit.clone()),
|
||||
typed_ir::ExprKind::Path(_) => todo!("evaluate path"),
|
||||
typed_ir::ExprKind::Call {
|
||||
called,
|
||||
args,
|
||||
genargs,
|
||||
} => todo!("evaluate call"),
|
||||
typed_ir::ExprKind::Call(_call) => todo!("evaluate call"),
|
||||
typed_ir::ExprKind::Match(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,10 +142,10 @@ impl Context {
|
|||
}
|
||||
Expression::Literal(lit) => {
|
||||
// TODO: make this a proper enum instead of having to match on everything
|
||||
let data = match lit.kind() {
|
||||
parser::tokens::TokenKind::Number => {
|
||||
let num = lit.span().fragment().parse().unwrap();
|
||||
self.types.make_elabnum_u32(num)
|
||||
let data = match lit.kind {
|
||||
parser::expression::LiteralKind::Num(num) => self.types.make_elabnum_u32(num),
|
||||
parser::expression::LiteralKind::Const(width, val) => {
|
||||
self.types.make_const_u32(width, val as u32)
|
||||
}
|
||||
_ => unreachable!("non-literal token in literal?"),
|
||||
};
|
||||
|
@ -161,11 +159,11 @@ impl Context {
|
|||
let a = self.type_expression(&op.a)?;
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Call {
|
||||
kind: typed_ir::ExprKind::Call(typed_ir::Call {
|
||||
called: self.callables.builtins.bitnot,
|
||||
args: vec![a],
|
||||
genargs: vec![],
|
||||
},
|
||||
}),
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
|
@ -173,11 +171,11 @@ impl Context {
|
|||
let (a, b) = (self.type_expression(&op.a)?, self.type_expression(&op.b)?);
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Call {
|
||||
kind: typed_ir::ExprKind::Call(typed_ir::Call {
|
||||
called: self.callables.builtins.xor,
|
||||
args: vec![a, b],
|
||||
genargs: vec![],
|
||||
},
|
||||
}),
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
|
@ -202,14 +200,34 @@ impl Context {
|
|||
.collect();
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Call {
|
||||
kind: typed_ir::ExprKind::Call(typed_ir::Call {
|
||||
called,
|
||||
args: args_resolved,
|
||||
genargs: genargs_resolved,
|
||||
},
|
||||
}),
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
Expression::BlockExpr(block) => match &**block {
|
||||
BlockExpr::IfElse(_) => todo!(),
|
||||
BlockExpr::Match(match_) => {
|
||||
let expr = self.type_expression(&match_.expr)?;
|
||||
let arms = match_
|
||||
.arms
|
||||
.iter()
|
||||
.map(|(cond, val)| {
|
||||
Ok((self.type_expression(cond)?, self.type_expression(val)?))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
let typed = typed_ir::Match { expr, arms };
|
||||
typed_ir::Expr {
|
||||
id,
|
||||
kind: typed_ir::ExprKind::Match(Box::new(typed)),
|
||||
typ: self.types.primitives.infer,
|
||||
}
|
||||
}
|
||||
BlockExpr::Block(_) => todo!(),
|
||||
},
|
||||
};
|
||||
Ok(t_expr)
|
||||
}
|
||||
|
@ -317,13 +335,13 @@ impl Context {
|
|||
typed_ir::ExprKind::Literal(lit) => expr.clone().with_type(lit.typ),
|
||||
// we can not see beyond this expression right now
|
||||
typed_ir::ExprKind::Path(_) => expr.clone(),
|
||||
typed_ir::ExprKind::Call {
|
||||
called,
|
||||
args,
|
||||
genargs,
|
||||
} => {
|
||||
let args_typed: Vec<_> = args.iter().map(|ex| self.infer_expr_types(ex)).collect();
|
||||
let callee_def = self.callables.get(*called);
|
||||
typed_ir::ExprKind::Call(call) => {
|
||||
let args_typed: Vec<_> = call
|
||||
.args
|
||||
.iter()
|
||||
.map(|ex| self.infer_expr_types(ex))
|
||||
.collect();
|
||||
let callee_def = self.callables.get(call.called);
|
||||
|
||||
let param_types: Vec<_> = callee_def.args.iter().map(|param| param.1).collect();
|
||||
let inferred_args: Vec<_> = param_types
|
||||
|
@ -358,11 +376,27 @@ impl Context {
|
|||
|
||||
let mut new_expr = expr.clone();
|
||||
new_expr.typ = new_type;
|
||||
new_expr.kind = typed_ir::ExprKind::Call {
|
||||
called: called.clone(),
|
||||
new_expr.kind = typed_ir::ExprKind::Call(typed_ir::Call {
|
||||
called: call.called.clone(),
|
||||
args: args_typed,
|
||||
genargs,
|
||||
});
|
||||
new_expr
|
||||
}
|
||||
typed_ir::ExprKind::Match(match_) => {
|
||||
let new_arms: Vec<_> = match_
|
||||
.arms
|
||||
.iter()
|
||||
.map(|(pat, val)| (self.infer_expr_types(pat), self.infer_expr_types(val)))
|
||||
.collect();
|
||||
// TODO: hacky hacky hacky
|
||||
let res_type = new_arms.first().unwrap().1.typ;
|
||||
let new_match = typed_ir::Match {
|
||||
expr: self.infer_expr_types(&match_.expr),
|
||||
arms: new_arms,
|
||||
};
|
||||
let mut new_expr = expr.clone().with_type(res_type);
|
||||
new_expr.kind = typed_ir::ExprKind::Match(Box::new(new_match));
|
||||
new_expr
|
||||
}
|
||||
}
|
||||
|
@ -429,20 +463,18 @@ impl Context {
|
|||
lit_str
|
||||
}
|
||||
typed_ir::ExprKind::Path(path) => format!("sig_{}", path.0),
|
||||
typed_ir::ExprKind::Call {
|
||||
called,
|
||||
args,
|
||||
genargs,
|
||||
} => {
|
||||
let args = args
|
||||
typed_ir::ExprKind::Call(call) => {
|
||||
let args = call
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
self.pretty_typed_expr(w, arg)?;
|
||||
Ok(format!("_{}", arg.id.0))
|
||||
})
|
||||
.collect::<Result<Vec<_>, std::fmt::Error>>()?;
|
||||
let callable = self.callables.get(*called);
|
||||
let genargs = genargs
|
||||
let callable = self.callables.get(call.called);
|
||||
let genargs = call
|
||||
.genargs
|
||||
.iter()
|
||||
.map(|param| {
|
||||
let mut type_str = String::new();
|
||||
|
@ -457,6 +489,23 @@ impl Context {
|
|||
args.join(", ")
|
||||
)
|
||||
}
|
||||
typed_ir::ExprKind::Match(match_) => {
|
||||
self.pretty_typed_expr(w, &match_.expr)?;
|
||||
let arms = match_
|
||||
.arms
|
||||
.iter()
|
||||
.map(|(pat, val)| {
|
||||
self.pretty_typed_expr(w, pat)?;
|
||||
self.pretty_typed_expr(w, val)?;
|
||||
Ok(format!(" _{} => _{}", pat.id.0, val.id.0))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
format!(
|
||||
"match (_{}) {{\n{}\n}}",
|
||||
&match_.expr.id.0,
|
||||
arms.join(",\n")
|
||||
)
|
||||
}
|
||||
};
|
||||
let mut type_pretty = String::new();
|
||||
self.types.pretty_type(&mut type_pretty, expr.typ)?;
|
||||
|
|
|
@ -17,22 +17,19 @@ fn lower_expression(
|
|||
module.add_wire(expr_wire);
|
||||
match &expr.kind {
|
||||
ExprKind::Path(def) => Ok(rtlil::SigSpec::Wire(format!("\\$sig_{}", def.0))),
|
||||
ExprKind::Call {
|
||||
called,
|
||||
args,
|
||||
genargs,
|
||||
} => {
|
||||
let args_resolved = args
|
||||
ExprKind::Call(call) => {
|
||||
let args_resolved = call
|
||||
.args
|
||||
.iter()
|
||||
.map(|expr| lower_expression(ctx, module, expr))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let callable = ctx.callables.get(*called);
|
||||
let callable = ctx.callables.get(call.called);
|
||||
let cell_id = module.make_genid(callable.name());
|
||||
|
||||
if *called == ctx.callables.builtins.xor {
|
||||
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
||||
let b_width = ctx.types.get_width(args[1].typ).unwrap();
|
||||
if call.called == ctx.callables.builtins.xor {
|
||||
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
||||
let b_width = ctx.types.get_width(call.args[1].typ).unwrap();
|
||||
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
||||
let mut cell = rtlil::Cell::new(&cell_id, "$xor");
|
||||
cell.add_param("\\A_SIGNED", "0");
|
||||
|
@ -44,8 +41,8 @@ fn lower_expression(
|
|||
cell.add_connection("\\B", &args_resolved[1]);
|
||||
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
||||
module.add_cell(cell);
|
||||
} else if *called == ctx.callables.builtins.reduce_or {
|
||||
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
||||
} else if call.called == ctx.callables.builtins.reduce_or {
|
||||
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
||||
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
||||
let mut cell = rtlil::Cell::new(&cell_id, "$reduce_or");
|
||||
cell.add_param("\\A_SIGNED", "0");
|
||||
|
@ -54,8 +51,8 @@ fn lower_expression(
|
|||
cell.add_connection("\\A", &args_resolved[0]);
|
||||
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
||||
module.add_cell(cell);
|
||||
} else if *called == ctx.callables.builtins.bitnot {
|
||||
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
||||
} else if call.called == ctx.callables.builtins.bitnot {
|
||||
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
||||
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
||||
let mut cell = rtlil::Cell::new(&cell_id, "$not");
|
||||
cell.add_param("\\A_SIGNED", "0");
|
||||
|
@ -72,6 +69,7 @@ fn lower_expression(
|
|||
todo!(),
|
||||
ctx.types.get_width(expr.typ).expect("signal has no size"),
|
||||
)),
|
||||
ExprKind::Match(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,15 +28,25 @@ pub struct Expr {
|
|||
pub typ: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Call {
|
||||
pub called: CallableId,
|
||||
pub args: Vec<Expr>,
|
||||
pub genargs: Vec<Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Match {
|
||||
pub expr: Expr,
|
||||
pub arms: Vec<(Expr, Expr)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExprKind {
|
||||
Literal(ElabData),
|
||||
Path(DefId),
|
||||
Call {
|
||||
called: CallableId,
|
||||
args: Vec<Expr>,
|
||||
genargs: Vec<Type>,
|
||||
},
|
||||
Call(Call),
|
||||
Match(Box<Match>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt::Debug;
|
||||
/// Alias for &TypeStruct to reduce repetition
|
||||
/// and make futura migration to interning
|
||||
|
@ -13,12 +14,12 @@ impl Debug for InternedType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypeStruct {
|
||||
kind: TypeKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum TypeKind {
|
||||
/// Elaboration-time types
|
||||
ElabType(ElabKind),
|
||||
|
@ -62,7 +63,7 @@ enum ElabValueData {
|
|||
}
|
||||
|
||||
/// Types that are only valid during Elaboration
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum ElabKind {
|
||||
/// general, unsized number type
|
||||
Num,
|
||||
|
@ -95,7 +96,7 @@ pub struct PrimitiveTypes {
|
|||
}
|
||||
|
||||
pub struct TypingContext {
|
||||
types: Vec<TypeStruct>,
|
||||
types: RefCell<Vec<TypeStruct>>,
|
||||
pub primitives: PrimitiveTypes,
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ impl TypingContext {
|
|||
infer: InternedType(2),
|
||||
};
|
||||
Self {
|
||||
types: vec![
|
||||
types: RefCell::new(vec![
|
||||
TypeStruct {
|
||||
kind: TypeKind::ElabType(ElabKind::Num),
|
||||
},
|
||||
|
@ -120,19 +121,19 @@ impl TypingContext {
|
|||
TypeStruct {
|
||||
kind: TypeKind::Infer,
|
||||
},
|
||||
],
|
||||
]),
|
||||
primitives,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, typ: TypeStruct) -> Type {
|
||||
let id = self.types.len();
|
||||
self.types.push(typ);
|
||||
pub fn add(&self, typ: TypeStruct) -> Type {
|
||||
let id = self.types.borrow().len();
|
||||
self.types.borrow_mut().push(typ);
|
||||
InternedType(id)
|
||||
}
|
||||
|
||||
pub fn get(&self, typ: Type) -> &TypeStruct {
|
||||
&self.types[typ.0]
|
||||
pub fn get(&self, typ: Type) -> TypeStruct {
|
||||
self.types.borrow()[typ.0].clone()
|
||||
}
|
||||
|
||||
pub fn make_elabnum_u32(&self, num: u32) -> ElabData {
|
||||
|
@ -142,7 +143,14 @@ impl TypingContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_logic_size(&mut self, width: u32) -> Type {
|
||||
pub fn make_const_u32(&self, width: u32, num: u32) -> ElabData {
|
||||
ElabData {
|
||||
typ: self.make_logic_size(width),
|
||||
value: ElabValue::Concrete(ElabValueData::U32(num)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_logic_size(&self, width: u32) -> Type {
|
||||
let widthnum = self.make_elabnum_u32(width);
|
||||
self.parameterize(self.primitives.logic, &[GenericArg::Elab(widthnum)])
|
||||
.unwrap()
|
||||
|
@ -171,7 +179,7 @@ impl TypingContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parameterize(&mut self, typ: Type, params: &[GenericArg]) -> Option<Type> {
|
||||
pub fn parameterize(&self, typ: Type, params: &[GenericArg]) -> Option<Type> {
|
||||
// TODO: return proper error type here
|
||||
match &self.get(typ).kind {
|
||||
// Elab types have no params yet
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
use nom::{
|
||||
branch::alt,
|
||||
combinator::map,
|
||||
error::context,
|
||||
multi::{many1, separated_list1},
|
||||
sequence::{delimited, separated_pair, tuple},
|
||||
};
|
||||
|
||||
use crate::parser::{
|
||||
assign_statement, expression,
|
||||
expression::{expression, Expression},
|
||||
tokens::{token, TokenKind as tk, TokenSpan},
|
||||
Assign, IResult, Span,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BlockExpr<'a> {
|
||||
IfElse(IfElseBlock),
|
||||
Match(MatchBlock<'a>),
|
||||
Block(Vec<BlockExpr<'a>>),
|
||||
}
|
||||
|
||||
// TODO: postponed because annoying to implement
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IfElseBlock {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MatchBlock<'a> {
|
||||
pub expr: Expression<'a>,
|
||||
pub arms: Vec<(Expression<'a>, Expression<'a>)>,
|
||||
}
|
||||
|
||||
fn match_arm(input: TokenSpan) -> IResult<TokenSpan, (Expression, Expression)> {
|
||||
separated_pair(expression, token(tk::FatArrow), expression)(input)
|
||||
}
|
||||
|
||||
fn match_block(input: TokenSpan) -> IResult<TokenSpan, MatchBlock> {
|
||||
context(
|
||||
"match block",
|
||||
map(
|
||||
tuple((
|
||||
token(tk::Match),
|
||||
delimited(token(tk::LParen), expression, token(tk::RParen)),
|
||||
delimited(
|
||||
token(tk::LBrace),
|
||||
separated_list1(token(tk::Comma), match_arm),
|
||||
token(tk::RBrace),
|
||||
),
|
||||
)),
|
||||
|(_, expr, arms)| MatchBlock { expr, arms },
|
||||
),
|
||||
)(input)
|
||||
}
|
||||
|
||||
pub fn block_expr(input: TokenSpan) -> IResult<TokenSpan, BlockExpr> {
|
||||
alt((map(match_block, BlockExpr::Match),))(input)
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
use super::block_expression::{block_expr, BlockExpr};
|
||||
use super::literals;
|
||||
use super::tokens::{token, Token, TokenKind as tk, TokenSpan};
|
||||
use super::{IResult, Span};
|
||||
use nom::{
|
||||
|
@ -7,6 +9,18 @@ use nom::{
|
|||
sequence::{delimited, preceded, separated_pair, tuple},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Literal<'a> {
|
||||
pub tok: Token<'a>,
|
||||
pub kind: LiteralKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LiteralKind {
|
||||
Num(u32),
|
||||
Const(u32, u64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Call<'a> {
|
||||
pub name: Span<'a>,
|
||||
|
@ -42,10 +56,11 @@ pub struct UnOp<'a> {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Expression<'a> {
|
||||
Path(&'a str),
|
||||
Literal(Token<'a>),
|
||||
Literal(Literal<'a>),
|
||||
UnOp(Box<UnOp<'a>>),
|
||||
BinOp(Box<BinOp<'a>>),
|
||||
Call(Box<Call<'a>>),
|
||||
BlockExpr(Box<BlockExpr<'a>>),
|
||||
}
|
||||
|
||||
/// expressions that can't be subdivided further
|
||||
|
@ -55,7 +70,19 @@ fn atom(input: TokenSpan) -> IResult<TokenSpan, Expression> {
|
|||
map(token(tk::Ident), |it| {
|
||||
Expression::Path(it.span().fragment())
|
||||
}),
|
||||
map(token(tk::Number), Expression::Literal),
|
||||
map(token(tk::Number), |tok| {
|
||||
Expression::Literal(Literal {
|
||||
tok,
|
||||
kind: LiteralKind::Num(tok.span().parse().expect("invalid literal")),
|
||||
})
|
||||
}),
|
||||
map(token(tk::Constant), |tok| {
|
||||
let (_, (width, val)) = literals::const_bits(tok.span()).expect("invalid literal");
|
||||
Expression::Literal(Literal {
|
||||
tok,
|
||||
kind: LiteralKind::Const(width, val),
|
||||
})
|
||||
}),
|
||||
delimited(token(tk::LParen), expression, token(tk::RParen)),
|
||||
))(input)
|
||||
}
|
||||
|
@ -119,11 +146,11 @@ pub fn call_item(input: TokenSpan) -> IResult<TokenSpan, Call> {
|
|||
)(input)
|
||||
}
|
||||
|
||||
/// parser combinators can not parse left-recursive grammars. To work around this, we split
|
||||
/// expressions into a recursive and non-recursive portion.
|
||||
/// Parsers reachable from this point must call expression_nonrecurse instead
|
||||
pub fn expression(input: TokenSpan) -> IResult<TokenSpan, Expression> {
|
||||
bitop(input)
|
||||
alt((
|
||||
bitop,
|
||||
map(block_expr, |blk| Expression::BlockExpr(Box::new(blk))),
|
||||
))(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,15 +1,27 @@
|
|||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::tag,
|
||||
character::complete::{alpha1, alphanumeric1, char, multispace0, one_of},
|
||||
character::complete::{alpha1, alphanumeric1, char, digit1, multispace0, one_of},
|
||||
combinator::{map, recognize},
|
||||
error::ParseError,
|
||||
multi::{many0, many1},
|
||||
sequence::{delimited, pair, preceded, terminated},
|
||||
sequence::{delimited, pair, preceded, separated_pair, terminated},
|
||||
};
|
||||
|
||||
use crate::parser::{IResult, Span};
|
||||
|
||||
pub fn const_bits(input: Span) -> IResult<Span, (u32, u64)> {
|
||||
map(
|
||||
separated_pair(digit1, char('\''), digit1),
|
||||
|(width, value): (Span, Span)| {
|
||||
(
|
||||
width.fragment().parse().expect("error parsing literal"),
|
||||
value.fragment().parse().expect("error parsing literal"),
|
||||
)
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
pub fn hexadecimal(input: Span) -> IResult<Span, u64> {
|
||||
map(
|
||||
preceded(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pub mod adt;
|
||||
pub mod block_expression;
|
||||
pub mod comb;
|
||||
pub mod declaration;
|
||||
pub mod error;
|
||||
|
|
|
@ -3,12 +3,11 @@ use nom::{
|
|||
combinator::map,
|
||||
error::context,
|
||||
multi::{many1, separated_list1},
|
||||
sequence::{delimited, separated_pair, tuple},
|
||||
sequence::{delimited, tuple},
|
||||
};
|
||||
|
||||
use crate::parser::{
|
||||
assign_statement, expression,
|
||||
expression::{expression, Expression},
|
||||
assign_statement,
|
||||
tokens::{token, TokenKind as tk, TokenSpan},
|
||||
Assign, IResult, Span,
|
||||
};
|
||||
|
@ -21,42 +20,7 @@ pub struct ProcBlock<'a> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum ProcStatement<'a> {
|
||||
IfElse(IfElseBlock),
|
||||
Assign(Assign<'a>),
|
||||
Match(MatchBlock<'a>),
|
||||
Block(Vec<ProcStatement<'a>>),
|
||||
}
|
||||
|
||||
// TODO: postponed because annoying to implement
|
||||
#[derive(Debug)]
|
||||
pub struct IfElseBlock {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MatchBlock<'a> {
|
||||
pub expr: Expression<'a>,
|
||||
pub arms: Vec<(Expression<'a>, ProcStatement<'a>)>,
|
||||
}
|
||||
|
||||
fn match_arm(input: TokenSpan) -> IResult<TokenSpan, (Expression, ProcStatement)> {
|
||||
separated_pair(expression, token(tk::FatArrow), proc_statement)(input)
|
||||
}
|
||||
|
||||
fn match_block(input: TokenSpan) -> IResult<TokenSpan, MatchBlock> {
|
||||
context(
|
||||
"match block",
|
||||
map(
|
||||
tuple((
|
||||
token(tk::Match),
|
||||
delimited(token(tk::LParen), expression, token(tk::RParen)),
|
||||
delimited(
|
||||
token(tk::LBrace),
|
||||
separated_list1(token(tk::Comma), match_arm),
|
||||
token(tk::RBrace),
|
||||
),
|
||||
)),
|
||||
|(_, expr, arms)| MatchBlock { expr, arms },
|
||||
),
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn statement_block(input: TokenSpan) -> IResult<TokenSpan, Vec<ProcStatement>> {
|
||||
|
@ -69,11 +33,7 @@ fn statement_block(input: TokenSpan) -> IResult<TokenSpan, Vec<ProcStatement>> {
|
|||
|
||||
/// parse a statement that is valid inside a proc block
|
||||
fn proc_statement(input: TokenSpan) -> IResult<TokenSpan, ProcStatement> {
|
||||
alt((
|
||||
map(match_block, ProcStatement::Match),
|
||||
map(statement_block, ProcStatement::Block),
|
||||
map(assign_statement, ProcStatement::Assign),
|
||||
))(input)
|
||||
alt((map(assign_statement, ProcStatement::Assign),))(input)
|
||||
}
|
||||
|
||||
pub fn proc_block(input: TokenSpan) -> IResult<TokenSpan, ProcBlock> {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use super::{
|
||||
error::{Error, InputPos},
|
||||
literals::{identifier, ws0},
|
||||
literals::{const_bits, identifier, ws0},
|
||||
IResult, Span,
|
||||
};
|
||||
use nom::{
|
||||
|
@ -77,6 +77,7 @@ pub enum TokenKind {
|
|||
// Literals
|
||||
Ident,
|
||||
Number,
|
||||
Constant,
|
||||
// Keywords
|
||||
Module,
|
||||
Assign,
|
||||
|
@ -186,6 +187,7 @@ fn lex_braces(input: Span) -> IResult<Span, Token> {
|
|||
fn lex_literals(input: Span) -> IResult<Span, Token> {
|
||||
map(
|
||||
consumed(alt((
|
||||
map(const_bits, |_| TokenKind::Constant),
|
||||
map(identifier, |_| TokenKind::Ident),
|
||||
map(digit1, |_| TokenKind::Number),
|
||||
))),
|
||||
|
|
Loading…
Reference in New Issue