Parse and format dbg

This commit is contained in:
Richard Feldman 2022-11-22 19:08:54 -05:00
parent ef5d83a42d
commit 49f8768271
No known key found for this signature in database
GPG Key ID: F1F21AA5B1D9E43B
13 changed files with 176 additions and 54 deletions

View File

@ -278,6 +278,7 @@ fn to_pending_def<'a>(
Type(TypeDef::Opaque { .. }) => internal_error!("opaques not implemented"),
Type(TypeDef::Ability { .. }) => todo_abilities!(),
Value(AstValueDef::Dbg { .. }) => todo!(),
Value(AstValueDef::Expect { .. }) => todo!(),
Value(AstValueDef::ExpectFx { .. }) => todo!(),

View File

@ -88,20 +88,21 @@ pub struct Annotation {
#[derive(Debug)]
pub(crate) struct CanDefs {
defs: Vec<Option<Def>>,
expects: Expects,
expects_fx: Expects,
dbgs: ExpectsOrDbgs,
expects: ExpectsOrDbgs,
expects_fx: ExpectsOrDbgs,
def_ordering: DefOrdering,
aliases: VecMap<Symbol, Alias>,
}
#[derive(Clone, Debug)]
pub struct Expects {
pub struct ExpectsOrDbgs {
pub conditions: Vec<Expr>,
pub regions: Vec<Region>,
pub preceding_comment: Vec<Region>,
}
impl Expects {
impl ExpectsOrDbgs {
fn with_capacity(capacity: usize) -> Self {
Self {
conditions: Vec::with_capacity(capacity),
@ -239,8 +240,8 @@ pub enum Declaration {
Declare(Def),
DeclareRec(Vec<Def>, IllegalCycleMark),
Builtin(Def),
Expects(Expects),
ExpectsFx(Expects),
Expects(ExpectsOrDbgs),
ExpectsFx(ExpectsOrDbgs),
/// If we know a cycle is illegal during canonicalization.
/// Otherwise we will try to detect this during solving; see [`IllegalCycleMark`].
InvalidCycle(Vec<CycleEntry>),
@ -1017,6 +1018,7 @@ fn canonicalize_value_defs<'a>(
// the ast::Expr values in pending_exprs for further canonicalization
// once we've finished assembling the entire scope.
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
let mut pending_dbgs = Vec::with_capacity(value_defs.len());
let mut pending_expects = Vec::with_capacity(value_defs.len());
let mut pending_expect_fx = Vec::with_capacity(value_defs.len());
@ -1030,10 +1032,12 @@ fn canonicalize_value_defs<'a>(
pending_value_defs.push(pending_def);
}
PendingValue::SignatureDefMismatch => { /* skip */ }
PendingValue::Dbg(pending_dbg) => {
pending_dbgs.push(pending_dbg);
}
PendingValue::Expect(pending_expect) => {
pending_expects.push(pending_expect);
}
PendingValue::ExpectFx(pending_expect) => {
pending_expect_fx.push(pending_expect);
}
@ -1094,8 +1098,23 @@ fn canonicalize_value_defs<'a>(
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
}
let mut expects = Expects::with_capacity(pending_expects.len());
let mut expects_fx = Expects::with_capacity(pending_expects.len());
let mut dbgs = ExpectsOrDbgs::with_capacity(pending_dbgs.len());
let mut expects = ExpectsOrDbgs::with_capacity(pending_expects.len());
let mut expects_fx = ExpectsOrDbgs::with_capacity(pending_expects.len());
for pending in pending_dbgs {
let (loc_can_condition, can_output) = canonicalize_expr(
env,
var_store,
scope,
pending.condition.region,
&pending.condition.value,
);
dbgs.push(loc_can_condition, pending.preceding_comment);
output.union(can_output);
}
for pending in pending_expects {
let (loc_can_condition, can_output) = canonicalize_expr(
@ -1127,6 +1146,7 @@ fn canonicalize_value_defs<'a>(
let can_defs = CanDefs {
defs,
dbgs,
expects,
expects_fx,
def_ordering,
@ -1534,6 +1554,7 @@ pub(crate) fn sort_can_defs_new(
) -> (Declarations, Output) {
let CanDefs {
defs,
dbgs,
expects,
expects_fx,
def_ordering,
@ -1750,6 +1771,7 @@ pub(crate) fn sort_can_defs(
) -> (Vec<Declaration>, Output) {
let CanDefs {
mut defs,
dbgs,
expects,
expects_fx,
def_ordering,
@ -2581,12 +2603,13 @@ fn to_pending_type_def<'a>(
enum PendingValue<'a> {
Def(PendingValueDef<'a>),
Expect(PendingExpect<'a>),
ExpectFx(PendingExpect<'a>),
Dbg(PendingExpectOrDbg<'a>),
Expect(PendingExpectOrDbg<'a>),
ExpectFx(PendingExpectOrDbg<'a>),
SignatureDefMismatch,
}
struct PendingExpect<'a> {
struct PendingExpectOrDbg<'a> {
condition: &'a Loc<ast::Expr<'a>>,
preceding_comment: Region,
}
@ -2684,10 +2707,18 @@ fn to_pending_value_def<'a>(
}
}
Dbg {
condition,
preceding_comment,
} => PendingValue::Dbg(PendingExpectOrDbg {
condition,
preceding_comment: *preceding_comment,
}),
Expect {
condition,
preceding_comment,
} => PendingValue::Expect(PendingExpect {
} => PendingValue::Expect(PendingExpectOrDbg {
condition,
preceding_comment: *preceding_comment,
}),
@ -2695,7 +2726,7 @@ fn to_pending_value_def<'a>(
ExpectFx {
condition,
preceding_comment,
} => PendingValue::ExpectFx(PendingExpect {
} => PendingValue::ExpectFx(PendingExpectOrDbg {
condition,
preceding_comment: *preceding_comment,
}),

View File

@ -82,6 +82,16 @@ fn desugar_value_def<'a>(arena: &'a Bump, def: &'a ValueDef<'a>) -> ValueDef<'a>
body_pattern,
body_expr: desugar_expr(arena, body_expr),
},
Dbg {
condition,
preceding_comment,
} => {
let desugared_condition = &*arena.alloc(desugar_expr(arena, condition));
Dbg {
condition: desugared_condition,
preceding_comment: *preceding_comment,
}
}
Expect {
condition,
preceding_comment,

View File

@ -168,6 +168,7 @@ impl<'a> Formattable for ValueDef<'a> {
AnnotatedBody { .. } => true,
Expect { condition, .. } => condition.is_multiline(),
ExpectFx { condition, .. } => condition.is_multiline(),
Dbg { condition, .. } => condition.is_multiline(),
}
}
@ -241,6 +242,7 @@ impl<'a> Formattable for ValueDef<'a> {
Body(loc_pattern, loc_expr) => {
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
}
Dbg { condition, .. } => fmt_dbg_in_def(buf, condition, self.is_multiline(), indent),
Expect { condition, .. } => fmt_expect(buf, condition, self.is_multiline(), indent),
ExpectFx { condition, .. } => {
fmt_expect_fx(buf, condition, self.is_multiline(), indent)
@ -294,6 +296,27 @@ impl<'a> Formattable for ValueDef<'a> {
}
}
fn fmt_dbg_in_def<'a, 'buf>(
buf: &mut Buf<'buf>,
condition: &'a Loc<Expr<'a>>,
is_multiline: bool,
indent: u16,
) {
buf.ensure_ends_with_newline();
buf.indent(indent);
buf.push_str("dbg");
let return_indent = if is_multiline {
buf.newline();
indent + INDENT
} else {
buf.spaces(1);
indent
};
condition.format(buf, return_indent);
}
fn fmt_expect<'a, 'buf>(
buf: &mut Buf<'buf>,
condition: &'a Loc<Expr<'a>>,

View File

@ -540,6 +540,13 @@ impl<'a> RemoveSpaces<'a> for ValueDef<'a> {
body_pattern: arena.alloc(body_pattern.remove_spaces(arena)),
body_expr: arena.alloc(body_expr.remove_spaces(arena)),
},
Dbg {
condition,
preceding_comment: _,
} => Dbg {
condition: arena.alloc(condition.remove_spaces(arena)),
preceding_comment: Region::zero(),
},
Expect {
condition,
preceding_comment: _,

View File

@ -200,6 +200,11 @@ fn generate_entry_docs<'a>(
ValueDef::Body(_, _) => (),
ValueDef::Dbg { .. } => {
// Don't generate docs for `dbg`s
}
ValueDef::Expect { .. } => {
// Don't generate docs for `expect`s
}

View File

@ -5,6 +5,7 @@
"as"
"is"
"expect"
"dbg"
"app"
"platform"

View File

@ -339,6 +339,11 @@ pub enum ValueDef<'a> {
body_expr: &'a Loc<Expr<'a>>,
},
Dbg {
condition: &'a Loc<Expr<'a>>,
preceding_comment: Region,
},
Expect {
condition: &'a Loc<Expr<'a>>,
preceding_comment: Region,

View File

@ -586,6 +586,7 @@ pub fn parse_single_def<'a>(
let start = state.pos();
let parse_dbg = crate::parser::keyword_e(crate::keyword::DBG, EExpect::Dbg);
let parse_expect_vanilla = crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect);
let parse_expect_fx = crate::parser::keyword_e(crate::keyword::EXPECT_FX, EExpect::Expect);
let parse_expect = either!(parse_expect_fx, parse_expect_vanilla);
@ -596,37 +597,35 @@ pub fn parse_single_def<'a>(
min_indent,
) {
Err((NoProgress, _)) => {
match parse_expect.parse(arena, state, min_indent) {
match parse_expect.parse(arena, state.clone(), min_indent) {
Err((_, _)) => {
// a hacky way to get expression-based error messages. TODO fix this
Ok((NoProgress, None, initial))
}
Ok((_, expect_flavor, state)) => {
let parse_def_expr =
space0_before_e(increment_min_indent(loc_expr()), EExpr::IndentEnd);
let (_, loc_def_expr, state) =
parse_def_expr.parse(arena, state, min_indent)?;
let end = loc_def_expr.region.end();
let region = Region::new(start, end);
// drop newlines before the preceding comment
let spaces_before_start = spaces_before_current_start.offset as usize;
let spaces_before_end = start.offset as usize;
let mut spaces_before_current_start = spaces_before_current_start;
for byte in &state.original_bytes()[spaces_before_start..spaces_before_end] {
match byte {
b' ' | b'\n' => {
spaces_before_current_start.offset += 1;
}
_ => break,
match parse_dbg.parse(arena, state, min_indent) {
Ok((_, _, state)) => parse_statement_inside_def(
arena,
state,
min_indent,
start,
spaces_before_current_start,
spaces_before_current,
|preceding_comment, loc_def_expr| ValueDef::Dbg {
condition: arena.alloc(loc_def_expr),
preceding_comment,
},
),
Err((_, _)) => {
// a hacky way to get expression-based error messages. TODO fix this
Ok((NoProgress, None, initial))
}
}
let preceding_comment = Region::new(spaces_before_current_start, start);
let value_def = match expect_flavor {
}
Ok((_, expect_flavor, state)) => parse_statement_inside_def(
arena,
state,
min_indent,
start,
spaces_before_current_start,
spaces_before_current,
|preceding_comment, loc_def_expr| match expect_flavor {
Either::Second(_) => ValueDef::Expect {
condition: arena.alloc(loc_def_expr),
preceding_comment,
@ -635,18 +634,8 @@ pub fn parse_single_def<'a>(
condition: arena.alloc(loc_def_expr),
preceding_comment,
},
};
Ok((
MadeProgress,
Some(SingleDef {
type_or_value: Either::Second(value_def),
region,
spaces_before: spaces_before_current,
}),
state,
))
}
},
),
}
}
Err((MadeProgress, _)) => {
@ -870,6 +859,49 @@ pub fn parse_single_def<'a>(
}
}
/// e.g. Things that can be on their own line in a def, e.g. `expect`, `expect-fx`, or `dbg`
fn parse_statement_inside_def<'a>(
arena: &'a Bump,
state: State<'a>,
min_indent: u32,
start: Position,
spaces_before_current_start: Position,
spaces_before_current: &'a [CommentOrNewline<'a>],
get_value_def: impl Fn(Region, Loc<Expr<'a>>) -> ValueDef<'a>,
) -> Result<(Progress, Option<SingleDef<'a>>, State<'a>), (Progress, EExpr<'a>)> {
let parse_def_expr = space0_before_e(increment_min_indent(loc_expr()), EExpr::IndentEnd);
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state, min_indent)?;
let end = loc_def_expr.region.end();
let region = Region::new(start, end);
// drop newlines before the preceding comment
let spaces_before_start = spaces_before_current_start.offset as usize;
let spaces_before_end = start.offset as usize;
let mut spaces_before_current_start = spaces_before_current_start;
for byte in &state.original_bytes()[spaces_before_start..spaces_before_end] {
match byte {
b' ' | b'\n' => {
spaces_before_current_start.offset += 1;
}
_ => break,
}
}
let preceding_comment = Region::new(spaces_before_current_start, start);
let value_def = get_value_def(preceding_comment, loc_def_expr);
Ok((
MadeProgress,
Some(SingleDef {
type_or_value: Either::Second(value_def),
region,
spaces_before: spaces_before_current,
}),
state,
))
}
// This is a macro only because trying to make it be a function caused lifetime issues.
#[macro_export]
macro_rules! join_ann_to_body {

View File

@ -4,6 +4,7 @@ pub const ELSE: &str = "else";
pub const WHEN: &str = "when";
pub const AS: &str = "as";
pub const IS: &str = "is";
pub const DBG: &str = "dbg";
pub const EXPECT: &str = "expect";
pub const EXPECT_FX: &str = "expect-fx";

View File

@ -544,6 +544,7 @@ pub enum EIf<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EExpect<'a> {
Space(BadInputError, Position),
Dbg(Position),
Expect(Position),
Condition(&'a EExpr<'a>, Position),
Continuation(&'a EExpr<'a>, Position),

View File

@ -33,6 +33,7 @@ pub enum Token {
KeywordEffects = 0b_0011_0000,
KeywordPlatform = 0b_0011_0001,
KeywordRequires = 0b_0011_0010,
KeywordDbg = 0b_0111_1011,
Comma = 0b_0100_0000,
Colon = 0b_0100_0001,
@ -417,6 +418,7 @@ fn lex_ident(uppercase: bool, bytes: &[u8]) -> (Token, usize) {
b"when" => Token::KeywordWhen,
b"as" => Token::KeywordAs,
b"is" => Token::KeywordIs,
b"dbg" => Token::KeywordDbg,
b"expect" => Token::KeywordExpect,
b"app" => Token::KeywordApp,
b"interface" => Token::KeywordInterface,

View File

@ -196,6 +196,9 @@ impl ReplState {
| ValueDef::AnnotatedBody { .. } => {
todo!("handle pattern other than identifier (which repl doesn't support)")
}
ValueDef::Dbg { .. } => {
todo!("handle receiving a `dbg` - what should the repl do for that?")
}
ValueDef::Expect { .. } => {
todo!("handle receiving an `expect` - what should the repl do for that?")
}