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