mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Merge pull request #3132 from rtfeldman/parse-def-soa
This commit is contained in:
commit
ea644c3360
23 changed files with 1577 additions and 816 deletions
|
@ -8,6 +8,90 @@ use crate::lang::{core::expr::expr_to_expr2::loc_expr_to_expr2, env::Env, scope:
|
||||||
|
|
||||||
use super::def2::Def2;
|
use super::def2::Def2;
|
||||||
|
|
||||||
|
fn spaces_to_comments(spaces: &[CommentOrNewline]) -> Option<String> {
|
||||||
|
if !spaces.is_empty() && !all_newlines(spaces) {
|
||||||
|
let mut all_comments_str = String::new();
|
||||||
|
|
||||||
|
for comment in spaces.iter().filter(|c_or_nl| !c_or_nl.is_newline()) {
|
||||||
|
all_comments_str.push_str(&comment.to_string_repr());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(all_comments_str)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toplevel_defs_to_defs2<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
scope: &mut Scope,
|
||||||
|
parsed_defs: roc_parse::ast::Defs<'a>,
|
||||||
|
region: Region,
|
||||||
|
) -> Vec<Def2> {
|
||||||
|
let mut result = Vec::with_capacity(parsed_defs.tags.len());
|
||||||
|
|
||||||
|
for (index, def) in parsed_defs.defs().enumerate() {
|
||||||
|
let mut def = match def {
|
||||||
|
Err(roc_parse::ast::ValueDef::Body(&loc_pattern, &loc_expr)) => {
|
||||||
|
let expr2 = loc_expr_to_expr2(arena, loc_expr, env, scope, region).0;
|
||||||
|
let expr_id = env.pool.add(expr2);
|
||||||
|
|
||||||
|
use roc_parse::ast::Pattern::*;
|
||||||
|
|
||||||
|
match loc_pattern.value {
|
||||||
|
Identifier(id_str) => {
|
||||||
|
let identifier_id =
|
||||||
|
env.ident_ids.get_or_insert(&Ident(IdentStr::from(id_str)));
|
||||||
|
|
||||||
|
// TODO support with annotation
|
||||||
|
Def2::ValueDef {
|
||||||
|
identifier_id,
|
||||||
|
expr_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
unimplemented!(
|
||||||
|
"I don't yet know how to convert the pattern {:?} into an expr2",
|
||||||
|
other
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other => {
|
||||||
|
unimplemented!(
|
||||||
|
"I don't know how to make an expr2 from this def yet: {:?}",
|
||||||
|
other
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let spaces_before = &parsed_defs.spaces[parsed_defs.space_before[index].indices()];
|
||||||
|
let spaces_after = &parsed_defs.spaces[parsed_defs.space_after[index].indices()];
|
||||||
|
|
||||||
|
if let Some(comments) = spaces_to_comments(spaces_before) {
|
||||||
|
let inner_def_id = env.pool.add(def);
|
||||||
|
def = Def2::CommentsBefore {
|
||||||
|
comments,
|
||||||
|
def_id: inner_def_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(comments) = spaces_to_comments(spaces_after) {
|
||||||
|
let inner_def_id = env.pool.add(def);
|
||||||
|
def = Def2::CommentsAfter {
|
||||||
|
comments,
|
||||||
|
def_id: inner_def_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(def)
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
pub fn defs_to_defs2<'a>(
|
pub fn defs_to_defs2<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
|
||||||
use crate::FormatMode;
|
use crate::FormatMode;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_error_macros::{internal_error, user_error};
|
use roc_error_macros::{internal_error, user_error};
|
||||||
use roc_fmt::def::fmt_def;
|
use roc_fmt::def::fmt_toplevel_defs;
|
||||||
use roc_fmt::module::fmt_module;
|
use roc_fmt::module::fmt_module;
|
||||||
use roc_fmt::spaces::RemoveSpaces;
|
use roc_fmt::spaces::RemoveSpaces;
|
||||||
use roc_fmt::{Ast, Buf};
|
use roc_fmt::{Ast, Buf};
|
||||||
|
@ -71,7 +71,7 @@ pub fn format(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), Str
|
||||||
user_error!("Unexpected parse failure when parsing this formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, e)
|
user_error!("Unexpected parse failure when parsing this formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, e)
|
||||||
}));
|
}));
|
||||||
let mut buf = Buf::new_in(&arena);
|
let mut buf = Buf::new_in(&arena);
|
||||||
fmt_all(&arena, &mut buf, ast);
|
fmt_all(&mut buf, ast);
|
||||||
|
|
||||||
let reparsed_ast = arena.alloc(parse_all(&arena, buf.as_str()).unwrap_or_else(|e| {
|
let reparsed_ast = arena.alloc(parse_all(&arena, buf.as_str()).unwrap_or_else(|e| {
|
||||||
let mut fail_file = file.clone();
|
let mut fail_file = file.clone();
|
||||||
|
@ -118,7 +118,7 @@ pub fn format(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), Str
|
||||||
|
|
||||||
// Now verify that the resultant formatting is _stable_ - i.e. that it doesn't change again if re-formatted
|
// Now verify that the resultant formatting is _stable_ - i.e. that it doesn't change again if re-formatted
|
||||||
let mut reformatted_buf = Buf::new_in(&arena);
|
let mut reformatted_buf = Buf::new_in(&arena);
|
||||||
fmt_all(&arena, &mut reformatted_buf, reparsed_ast);
|
fmt_all(&mut reformatted_buf, reparsed_ast);
|
||||||
if buf.as_str() != reformatted_buf.as_str() {
|
if buf.as_str() != reformatted_buf.as_str() {
|
||||||
let mut unstable_1_file = file.clone();
|
let mut unstable_1_file = file.clone();
|
||||||
unstable_1_file.set_extension("roc-format-unstable-1");
|
unstable_1_file.set_extension("roc-format-unstable-1");
|
||||||
|
@ -163,11 +163,10 @@ fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'
|
||||||
Ok(Ast { module, defs })
|
Ok(Ast { module, defs })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_all<'a>(arena: &'a Bump, buf: &mut Buf<'a>, ast: &'a Ast) {
|
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a Ast) {
|
||||||
fmt_module(buf, &ast.module);
|
fmt_module(buf, &ast.module);
|
||||||
for def in &ast.defs {
|
|
||||||
fmt_def(buf, arena.alloc(def.value), 0);
|
fmt_toplevel_defs(buf, &ast.defs, 0);
|
||||||
}
|
|
||||||
|
|
||||||
buf.fmt_end_of_file();
|
buf.fmt_end_of_file();
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,6 +465,197 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
scope.register_debug_idents();
|
scope.register_debug_idents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (aliases, symbols_introduced) = canonicalize_type_defs(
|
||||||
|
env,
|
||||||
|
&mut output,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
pending_type_defs,
|
||||||
|
pattern_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now that we have the scope completely assembled, and shadowing resolved,
|
||||||
|
// we're ready to canonicalize any body exprs.
|
||||||
|
canonicalize_value_defs(
|
||||||
|
env,
|
||||||
|
output,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
&value_defs,
|
||||||
|
pattern_type,
|
||||||
|
aliases,
|
||||||
|
symbols_introduced,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn canonicalize_toplevel_defs<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
mut output: Output,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
scope: &mut Scope,
|
||||||
|
loc_defs: &'a mut roc_parse::ast::Defs<'a>,
|
||||||
|
pattern_type: PatternType,
|
||||||
|
) -> (CanDefs, Output, MutMap<Symbol, Region>) {
|
||||||
|
// Canonicalizing defs while detecting shadowing involves a multi-step process:
|
||||||
|
//
|
||||||
|
// 1. Go through each of the patterns.
|
||||||
|
// 2. For each identifier pattern, get the scope.symbol() for the ident. (That symbol will use the home module for its module.)
|
||||||
|
// 3. If that symbol is already in scope, then we're about to shadow it. Error!
|
||||||
|
// 4. Otherwise, add it to the scope immediately, so we can detect shadowing within the same
|
||||||
|
// pattern (e.g. (Foo a a) = ...)
|
||||||
|
// 5. Add this canonicalized pattern and its corresponding ast::Expr to pending_exprs.
|
||||||
|
// 5. Once every pattern has been processed and added to scope, go back and canonicalize the exprs from
|
||||||
|
// pending_exprs, this time building up a canonical def for each one.
|
||||||
|
//
|
||||||
|
// This way, whenever any expr is doing lookups, it knows everything that's in scope -
|
||||||
|
// even defs that appear after it in the source.
|
||||||
|
//
|
||||||
|
// This naturally handles recursion too, because a given expr which refers
|
||||||
|
// to itself won't be processed until after its def has been added to scope.
|
||||||
|
|
||||||
|
let mut pending_type_defs = Vec::with_capacity(loc_defs.type_defs.len());
|
||||||
|
let mut value_defs = Vec::with_capacity(loc_defs.value_defs.len());
|
||||||
|
|
||||||
|
for (index, either_index) in loc_defs.tags.iter().enumerate() {
|
||||||
|
match either_index.split() {
|
||||||
|
Ok(type_index) => {
|
||||||
|
let type_def = &loc_defs.type_defs[type_index.index()];
|
||||||
|
pending_type_defs.push(to_pending_type_def(env, type_def, scope, pattern_type));
|
||||||
|
}
|
||||||
|
Err(value_index) => {
|
||||||
|
let value_def = &loc_defs.value_defs[value_index.index()];
|
||||||
|
let region = loc_defs.regions[index];
|
||||||
|
value_defs.push(Loc::at(region, value_def));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
scope.register_debug_idents();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (aliases, symbols_introduced) = canonicalize_type_defs(
|
||||||
|
env,
|
||||||
|
&mut output,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
pending_type_defs,
|
||||||
|
pattern_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now that we have the scope completely assembled, and shadowing resolved,
|
||||||
|
// we're ready to canonicalize any body exprs.
|
||||||
|
canonicalize_value_defs(
|
||||||
|
env,
|
||||||
|
output,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
&value_defs,
|
||||||
|
pattern_type,
|
||||||
|
aliases,
|
||||||
|
symbols_introduced,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn canonicalize_value_defs<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
mut output: Output,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
scope: &mut Scope,
|
||||||
|
value_defs: &[Loc<&'a roc_parse::ast::ValueDef<'a>>],
|
||||||
|
pattern_type: PatternType,
|
||||||
|
mut aliases: VecMap<Symbol, Alias>,
|
||||||
|
mut symbols_introduced: MutMap<Symbol, Region>,
|
||||||
|
) -> (CanDefs, Output, MutMap<Symbol, Region>) {
|
||||||
|
// Canonicalize all the patterns, record shadowing problems, and store
|
||||||
|
// 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());
|
||||||
|
for loc_def in value_defs {
|
||||||
|
let mut new_output = Output::default();
|
||||||
|
match to_pending_value_def(
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
loc_def.value,
|
||||||
|
scope,
|
||||||
|
&mut new_output,
|
||||||
|
pattern_type,
|
||||||
|
) {
|
||||||
|
None => { /* skip */ }
|
||||||
|
Some(pending_def) => {
|
||||||
|
// Record the ast::Expr for later. We'll do another pass through these
|
||||||
|
// once we have the entire scope assembled. If we were to canonicalize
|
||||||
|
// the exprs right now, they wouldn't have symbols in scope from defs
|
||||||
|
// that get would have gotten added later in the defs list!
|
||||||
|
pending_value_defs.push(pending_def);
|
||||||
|
output.union(new_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len());
|
||||||
|
|
||||||
|
for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
|
||||||
|
for (s, r) in BindingsFromPattern::new(pending_def.loc_pattern()) {
|
||||||
|
// store the top-level defs, used to ensure that closures won't capture them
|
||||||
|
if let PatternType::TopLevelDef = pattern_type {
|
||||||
|
env.top_level_symbols.insert(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols_introduced.insert(s, r);
|
||||||
|
|
||||||
|
debug_assert_eq!(env.home, s.module_id());
|
||||||
|
debug_assert!(
|
||||||
|
!symbol_to_index.iter().any(|(id, _)| *id == s.ident_id()),
|
||||||
|
"{:?}",
|
||||||
|
s
|
||||||
|
);
|
||||||
|
|
||||||
|
symbol_to_index.push((s.ident_id(), def_index as u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let capacity = pending_value_defs.len();
|
||||||
|
let mut defs = Vec::with_capacity(capacity);
|
||||||
|
let mut def_ordering = DefOrdering::from_symbol_to_id(env.home, symbol_to_index, capacity);
|
||||||
|
|
||||||
|
for (def_id, pending_def) in pending_value_defs.into_iter().enumerate() {
|
||||||
|
let temp_output = canonicalize_pending_value_def(
|
||||||
|
env,
|
||||||
|
pending_def,
|
||||||
|
output,
|
||||||
|
scope,
|
||||||
|
var_store,
|
||||||
|
pattern_type,
|
||||||
|
&mut aliases,
|
||||||
|
);
|
||||||
|
|
||||||
|
output = temp_output.output;
|
||||||
|
|
||||||
|
defs.push(Some(temp_output.def));
|
||||||
|
|
||||||
|
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
||||||
|
}
|
||||||
|
|
||||||
|
let can_defs = CanDefs {
|
||||||
|
defs,
|
||||||
|
def_ordering,
|
||||||
|
aliases,
|
||||||
|
};
|
||||||
|
|
||||||
|
(can_defs, output, symbols_introduced)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonicalize_type_defs<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
output: &mut Output,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
scope: &mut Scope,
|
||||||
|
pending_type_defs: Vec<PendingTypeDef<'a>>,
|
||||||
|
pattern_type: PatternType,
|
||||||
|
) -> (VecMap<Symbol, Alias>, MutMap<Symbol, Region>) {
|
||||||
enum TypeDef<'a> {
|
enum TypeDef<'a> {
|
||||||
Alias(
|
Alias(
|
||||||
Loc<Symbol>,
|
Loc<Symbol>,
|
||||||
|
@ -547,7 +738,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
TypeDef::Alias(name, vars, ann) => {
|
TypeDef::Alias(name, vars, ann) => {
|
||||||
let alias = canonicalize_alias(
|
let alias = canonicalize_alias(
|
||||||
env,
|
env,
|
||||||
&mut output,
|
output,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
&pending_abilities_in_scope,
|
&pending_abilities_in_scope,
|
||||||
|
@ -565,7 +756,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
TypeDef::Opaque(name, vars, ann, derived) => {
|
TypeDef::Opaque(name, vars, ann, derived) => {
|
||||||
let alias_and_derives = canonicalize_opaque(
|
let alias_and_derives = canonicalize_opaque(
|
||||||
env,
|
env,
|
||||||
&mut output,
|
output,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
&pending_abilities_in_scope,
|
&pending_abilities_in_scope,
|
||||||
|
@ -590,7 +781,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
|
|
||||||
// Now that we know the alias dependency graph, we can try to insert recursion variables
|
// Now that we know the alias dependency graph, we can try to insert recursion variables
|
||||||
// where aliases are recursive tag unions, or detect illegal recursions.
|
// where aliases are recursive tag unions, or detect illegal recursions.
|
||||||
let mut aliases = correct_mutual_recursive_type_alias(env, aliases, var_store);
|
let aliases = correct_mutual_recursive_type_alias(env, aliases, var_store);
|
||||||
|
|
||||||
for (symbol, alias) in aliases.iter() {
|
for (symbol, alias) in aliases.iter() {
|
||||||
scope.add_alias(
|
scope.add_alias(
|
||||||
|
@ -605,7 +796,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
// Resolve all pending abilities, to add them to scope.
|
// Resolve all pending abilities, to add them to scope.
|
||||||
resolve_abilities(
|
resolve_abilities(
|
||||||
env,
|
env,
|
||||||
&mut output,
|
output,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
abilities,
|
abilities,
|
||||||
|
@ -613,89 +804,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
pattern_type,
|
pattern_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Now that we have the scope completely assembled, and shadowing resolved,
|
(aliases, symbols_introduced)
|
||||||
// we're ready to canonicalize any body exprs.
|
|
||||||
|
|
||||||
// Canonicalize all the patterns, record shadowing problems, and store
|
|
||||||
// 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());
|
|
||||||
for loc_def in value_defs.into_iter() {
|
|
||||||
let mut new_output = Output::default();
|
|
||||||
match to_pending_value_def(
|
|
||||||
env,
|
|
||||||
var_store,
|
|
||||||
loc_def.value,
|
|
||||||
scope,
|
|
||||||
&mut new_output,
|
|
||||||
pattern_type,
|
|
||||||
) {
|
|
||||||
None => { /* skip */ }
|
|
||||||
Some(pending_def) => {
|
|
||||||
// Record the ast::Expr for later. We'll do another pass through these
|
|
||||||
// once we have the entire scope assembled. If we were to canonicalize
|
|
||||||
// the exprs right now, they wouldn't have symbols in scope from defs
|
|
||||||
// that get would have gotten added later in the defs list!
|
|
||||||
pending_value_defs.push(pending_def);
|
|
||||||
output.union(new_output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len());
|
|
||||||
|
|
||||||
for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
|
|
||||||
for (s, r) in BindingsFromPattern::new(pending_def.loc_pattern()) {
|
|
||||||
// store the top-level defs, used to ensure that closures won't capture them
|
|
||||||
if let PatternType::TopLevelDef = pattern_type {
|
|
||||||
env.top_level_symbols.insert(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
symbols_introduced.insert(s, r);
|
|
||||||
|
|
||||||
debug_assert_eq!(env.home, s.module_id());
|
|
||||||
debug_assert!(
|
|
||||||
!symbol_to_index.iter().any(|(id, _)| *id == s.ident_id()),
|
|
||||||
"{:?}",
|
|
||||||
s
|
|
||||||
);
|
|
||||||
|
|
||||||
symbol_to_index.push((s.ident_id(), def_index as u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let capacity = pending_value_defs.len();
|
|
||||||
let mut defs = Vec::with_capacity(capacity);
|
|
||||||
let mut def_ordering = DefOrdering::from_symbol_to_id(env.home, symbol_to_index, capacity);
|
|
||||||
|
|
||||||
for (def_id, pending_def) in pending_value_defs.into_iter().enumerate() {
|
|
||||||
let temp_output = canonicalize_pending_value_def(
|
|
||||||
env,
|
|
||||||
pending_def,
|
|
||||||
output,
|
|
||||||
scope,
|
|
||||||
var_store,
|
|
||||||
pattern_type,
|
|
||||||
&mut aliases,
|
|
||||||
);
|
|
||||||
|
|
||||||
output = temp_output.output;
|
|
||||||
|
|
||||||
defs.push(Some(temp_output.def));
|
|
||||||
|
|
||||||
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
CanDefs {
|
|
||||||
defs,
|
|
||||||
def_ordering,
|
|
||||||
// The result needs a thread-safe `SendMap`
|
|
||||||
aliases,
|
|
||||||
},
|
|
||||||
output,
|
|
||||||
symbols_introduced,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve all pending abilities, to add them to scope.
|
/// Resolve all pending abilities, to add them to scope.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::abilities::AbilitiesStore;
|
use crate::abilities::AbilitiesStore;
|
||||||
use crate::annotation::canonicalize_annotation;
|
use crate::annotation::canonicalize_annotation;
|
||||||
use crate::def::{canonicalize_defs, sort_can_defs, Declaration, Def};
|
use crate::def::{canonicalize_toplevel_defs, sort_can_defs, Declaration, Def};
|
||||||
use crate::effect_module::HostedGeneratedFunctions;
|
use crate::effect_module::HostedGeneratedFunctions;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::expr::{ClosureData, Expr, Output, PendingDerives};
|
use crate::expr::{ClosureData, Expr, Output, PendingDerives};
|
||||||
use crate::operator::desugar_def;
|
use crate::operator::desugar_toplevel_defs;
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
@ -12,7 +12,7 @@ use roc_collections::{MutMap, SendMap, VecSet};
|
||||||
use roc_module::ident::Ident;
|
use roc_module::ident::Ident;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::{IdentIds, IdentIdsByModule, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, IdentIdsByModule, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_parse::ast::{self, TypeAnnotation};
|
use roc_parse::ast::{Defs, TypeAnnotation};
|
||||||
use roc_parse::header::HeaderFor;
|
use roc_parse::header::HeaderFor;
|
||||||
use roc_parse::pattern::PatternType;
|
use roc_parse::pattern::PatternType;
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
|
@ -160,7 +160,7 @@ fn has_no_implementation(expr: &Expr) -> bool {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn canonicalize_module_defs<'a>(
|
pub fn canonicalize_module_defs<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
loc_defs: &'a [Loc<ast::Def<'a>>],
|
loc_defs: &'a mut Defs<'a>,
|
||||||
header_for: &roc_parse::header::HeaderFor,
|
header_for: &roc_parse::header::HeaderFor,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
module_ids: &'a ModuleIds,
|
module_ids: &'a ModuleIds,
|
||||||
|
@ -198,15 +198,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||||
// operators, and then again on *their* nested operators, ultimately applying the
|
// operators, and then again on *their* nested operators, ultimately applying the
|
||||||
// rules multiple times unnecessarily.
|
// rules multiple times unnecessarily.
|
||||||
let mut desugared =
|
desugar_toplevel_defs(arena, loc_defs);
|
||||||
bumpalo::collections::Vec::with_capacity_in(loc_defs.len() + num_deps, arena);
|
|
||||||
|
|
||||||
for loc_def in loc_defs.iter() {
|
|
||||||
desugared.push(&*arena.alloc(Loc {
|
|
||||||
value: desugar_def(arena, &loc_def.value),
|
|
||||||
region: loc_def.region,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut lookups = Vec::with_capacity(num_deps);
|
let mut lookups = Vec::with_capacity(num_deps);
|
||||||
let mut rigid_variables = RigidVariables::default();
|
let mut rigid_variables = RigidVariables::default();
|
||||||
|
@ -282,12 +274,12 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (defs, output, symbols_introduced) = canonicalize_defs(
|
let (defs, output, symbols_introduced) = canonicalize_toplevel_defs(
|
||||||
&mut env,
|
&mut env,
|
||||||
Output::default(),
|
Output::default(),
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
&desugared,
|
loc_defs,
|
||||||
PatternType::TopLevelDef,
|
PatternType::TopLevelDef,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,12 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn desugar_toplevel_defs<'a>(arena: &'a Bump, defs: &mut roc_parse::ast::Defs<'a>) {
|
||||||
|
for value_def in defs.value_defs.iter_mut() {
|
||||||
|
*value_def = desugar_value_def(arena, arena.alloc(*value_def));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reorder the expression tree based on operator precedence and associativity rules,
|
/// Reorder the expression tree based on operator precedence and associativity rules,
|
||||||
/// then replace the BinOp nodes with Apply nodes. Also drop SpaceBefore and SpaceAfter nodes.
|
/// then replace the BinOp nodes with Apply nodes. Also drop SpaceBefore and SpaceAfter nodes.
|
||||||
pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc<Expr<'a>> {
|
pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc<Expr<'a>> {
|
||||||
|
|
|
@ -3,37 +3,49 @@ use crate::pattern::fmt_pattern;
|
||||||
use crate::spaces::{fmt_spaces, INDENT};
|
use crate::spaces::{fmt_spaces, INDENT};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
AbilityMember, Def, Expr, ExtractSpaces, Pattern, TypeAnnotation, TypeHeader,
|
AbilityMember, Def, Defs, Expr, ExtractSpaces, Pattern, TypeAnnotation, TypeDef, TypeHeader,
|
||||||
|
ValueDef,
|
||||||
};
|
};
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
/// A Located formattable value is also formattable
|
/// A Located formattable value is also formattable
|
||||||
impl<'a> Formattable for Def<'a> {
|
|
||||||
|
impl<'a> Formattable for Defs<'a> {
|
||||||
|
fn is_multiline(&self) -> bool {
|
||||||
|
!self.tags.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_with_options<'buf>(
|
||||||
|
&self,
|
||||||
|
buf: &mut Buf<'buf>,
|
||||||
|
_parens: Parens,
|
||||||
|
_newlines: Newlines,
|
||||||
|
indent: u16,
|
||||||
|
) {
|
||||||
|
for (index, def) in self.defs().enumerate() {
|
||||||
|
let spaces_before = &self.spaces[self.space_before[index].indices()];
|
||||||
|
let spaces_after = &self.spaces[self.space_after[index].indices()];
|
||||||
|
|
||||||
|
fmt_spaces(buf, spaces_before.iter(), indent);
|
||||||
|
|
||||||
|
match def {
|
||||||
|
Ok(type_def) => type_def.format(buf, indent),
|
||||||
|
Err(value_def) => value_def.format(buf, indent),
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_spaces(buf, spaces_after.iter(), indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Formattable for TypeDef<'a> {
|
||||||
fn is_multiline(&self) -> bool {
|
fn is_multiline(&self) -> bool {
|
||||||
use roc_parse::ast::Def::*;
|
|
||||||
use roc_parse::ast::TypeDef::*;
|
use roc_parse::ast::TypeDef::*;
|
||||||
use roc_parse::ast::ValueDef::*;
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Type(def) => match def {
|
Alias { ann, .. } => ann.is_multiline(),
|
||||||
Alias { ann, .. } => ann.is_multiline(),
|
Opaque { typ, .. } => typ.is_multiline(),
|
||||||
Opaque { typ, .. } => typ.is_multiline(),
|
Ability { members, .. } => members.iter().any(|d| d.is_multiline()),
|
||||||
Ability { members, .. } => members.iter().any(|d| d.is_multiline()),
|
|
||||||
},
|
|
||||||
Value(def) => match def {
|
|
||||||
Annotation(loc_pattern, loc_annotation) => {
|
|
||||||
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
|
||||||
}
|
|
||||||
Body(loc_pattern, loc_expr) => {
|
|
||||||
loc_pattern.is_multiline() || loc_expr.is_multiline()
|
|
||||||
}
|
|
||||||
AnnotatedBody { .. } => true,
|
|
||||||
Expect(loc_expr) => loc_expr.is_multiline(),
|
|
||||||
},
|
|
||||||
SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => {
|
|
||||||
spaces.iter().any(|s| s.is_comment()) || sub_def.is_multiline()
|
|
||||||
}
|
|
||||||
NotYetImplemented(s) => todo!("{}", s),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,218 +56,268 @@ impl<'a> Formattable for Def<'a> {
|
||||||
_newlines: Newlines,
|
_newlines: Newlines,
|
||||||
indent: u16,
|
indent: u16,
|
||||||
) {
|
) {
|
||||||
use roc_parse::ast::Def::*;
|
|
||||||
use roc_parse::ast::TypeDef::*;
|
use roc_parse::ast::TypeDef::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Alias {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
ann,
|
||||||
|
} => {
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push_str(name.value);
|
||||||
|
|
||||||
|
for var in *vars {
|
||||||
|
buf.spaces(1);
|
||||||
|
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(" :");
|
||||||
|
buf.spaces(1);
|
||||||
|
|
||||||
|
ann.format(buf, indent + INDENT)
|
||||||
|
}
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
typ: ann,
|
||||||
|
derived,
|
||||||
|
} => {
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push_str(name.value);
|
||||||
|
|
||||||
|
for var in *vars {
|
||||||
|
buf.spaces(1);
|
||||||
|
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(" :=");
|
||||||
|
buf.spaces(1);
|
||||||
|
|
||||||
|
let ann_is_where_clause =
|
||||||
|
matches!(ann.extract_spaces().item, TypeAnnotation::Where(..));
|
||||||
|
|
||||||
|
let ann_has_spaces_before = matches!(&ann.value, TypeAnnotation::SpaceBefore(..));
|
||||||
|
|
||||||
|
// Always put the has-derived clause on a newline if it is itself multiline, or
|
||||||
|
// the annotation has a where-has clause.
|
||||||
|
let derived_multiline = if let Some(derived) = derived {
|
||||||
|
!derived.value.is_empty() && (derived.is_multiline() || ann_is_where_clause)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let make_multiline = ann.is_multiline() || derived_multiline;
|
||||||
|
|
||||||
|
// If the annotation has spaces before, a newline will already be printed.
|
||||||
|
if make_multiline && !ann_has_spaces_before {
|
||||||
|
buf.newline();
|
||||||
|
buf.indent(indent + INDENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ann.format(buf, indent + INDENT);
|
||||||
|
|
||||||
|
if let Some(derived) = derived {
|
||||||
|
if !make_multiline {
|
||||||
|
buf.spaces(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
derived.format_with_options(
|
||||||
|
buf,
|
||||||
|
Parens::NotNeeded,
|
||||||
|
Newlines::from_bool(make_multiline),
|
||||||
|
indent + INDENT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ability {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
loc_has: _,
|
||||||
|
members,
|
||||||
|
} => {
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push_str(name.value);
|
||||||
|
for var in *vars {
|
||||||
|
buf.spaces(1);
|
||||||
|
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(" has");
|
||||||
|
|
||||||
|
if !self.is_multiline() {
|
||||||
|
debug_assert_eq!(members.len(), 1);
|
||||||
|
buf.push_str(" ");
|
||||||
|
members[0].format(buf, indent + INDENT);
|
||||||
|
} else {
|
||||||
|
for demand in members.iter() {
|
||||||
|
buf.newline();
|
||||||
|
buf.indent(indent + INDENT);
|
||||||
|
demand.format(buf, indent + INDENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Formattable for ValueDef<'a> {
|
||||||
|
fn is_multiline(&self) -> bool {
|
||||||
use roc_parse::ast::ValueDef::*;
|
use roc_parse::ast::ValueDef::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Type(def) => match def {
|
Annotation(loc_pattern, loc_annotation) => {
|
||||||
Alias {
|
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
||||||
header: TypeHeader { name, vars },
|
}
|
||||||
ann,
|
Body(loc_pattern, loc_expr) => loc_pattern.is_multiline() || loc_expr.is_multiline(),
|
||||||
} => {
|
AnnotatedBody { .. } => true,
|
||||||
buf.indent(indent);
|
Expect(loc_expr) => loc_expr.is_multiline(),
|
||||||
buf.push_str(name.value);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for var in *vars {
|
fn format_with_options<'buf>(
|
||||||
buf.spaces(1);
|
&self,
|
||||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
buf: &mut Buf<'buf>,
|
||||||
}
|
_parens: Parens,
|
||||||
|
_newlines: Newlines,
|
||||||
|
indent: u16,
|
||||||
|
) {
|
||||||
|
use roc_parse::ast::ValueDef::*;
|
||||||
|
match self {
|
||||||
|
Annotation(loc_pattern, loc_annotation) => {
|
||||||
|
loc_pattern.format(buf, indent);
|
||||||
|
|
||||||
|
if loc_annotation.is_multiline() {
|
||||||
buf.push_str(" :");
|
buf.push_str(" :");
|
||||||
buf.spaces(1);
|
|
||||||
|
|
||||||
ann.format(buf, indent + INDENT)
|
let should_outdent = match loc_annotation.value {
|
||||||
}
|
TypeAnnotation::SpaceBefore(sub_def, spaces) => match sub_def {
|
||||||
Opaque {
|
TypeAnnotation::Record { .. } | TypeAnnotation::TagUnion { .. } => {
|
||||||
header: TypeHeader { name, vars },
|
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
|
||||||
typ: ann,
|
is_only_newlines && sub_def.is_multiline()
|
||||||
derived,
|
}
|
||||||
} => {
|
_ => false,
|
||||||
buf.indent(indent);
|
},
|
||||||
buf.push_str(name.value);
|
TypeAnnotation::Record { .. } | TypeAnnotation::TagUnion { .. } => true,
|
||||||
|
_ => false,
|
||||||
for var in *vars {
|
|
||||||
buf.spaces(1);
|
|
||||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str(" :=");
|
|
||||||
buf.spaces(1);
|
|
||||||
|
|
||||||
let ann_is_where_clause =
|
|
||||||
matches!(ann.extract_spaces().item, TypeAnnotation::Where(..));
|
|
||||||
|
|
||||||
let ann_has_spaces_before =
|
|
||||||
matches!(&ann.value, TypeAnnotation::SpaceBefore(..));
|
|
||||||
|
|
||||||
// Always put the has-derived clause on a newline if it is itself multiline, or
|
|
||||||
// the annotation has a where-has clause.
|
|
||||||
let derived_multiline = if let Some(derived) = derived {
|
|
||||||
!derived.value.is_empty() && (derived.is_multiline() || ann_is_where_clause)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let make_multiline = ann.is_multiline() || derived_multiline;
|
if should_outdent {
|
||||||
|
|
||||||
// If the annotation has spaces before, a newline will already be printed.
|
|
||||||
if make_multiline && !ann_has_spaces_before {
|
|
||||||
buf.newline();
|
|
||||||
buf.indent(indent + INDENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
ann.format(buf, indent + INDENT);
|
|
||||||
|
|
||||||
if let Some(derived) = derived {
|
|
||||||
if !make_multiline {
|
|
||||||
buf.spaces(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
derived.format_with_options(
|
|
||||||
buf,
|
|
||||||
Parens::NotNeeded,
|
|
||||||
Newlines::from_bool(make_multiline),
|
|
||||||
indent + INDENT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ability {
|
|
||||||
header: TypeHeader { name, vars },
|
|
||||||
loc_has: _,
|
|
||||||
members,
|
|
||||||
} => {
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(name.value);
|
|
||||||
for var in *vars {
|
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
match loc_annotation.value {
|
||||||
}
|
TypeAnnotation::SpaceBefore(sub_def, _) => {
|
||||||
|
sub_def.format_with_options(
|
||||||
buf.push_str(" has");
|
buf,
|
||||||
|
Parens::NotNeeded,
|
||||||
if !self.is_multiline() {
|
Newlines::No,
|
||||||
debug_assert_eq!(members.len(), 1);
|
indent,
|
||||||
buf.push_str(" ");
|
);
|
||||||
members[0].format(buf, indent + INDENT);
|
}
|
||||||
} else {
|
_ => {
|
||||||
for demand in members.iter() {
|
loc_annotation.format_with_options(
|
||||||
buf.newline();
|
buf,
|
||||||
buf.indent(indent + INDENT);
|
Parens::NotNeeded,
|
||||||
demand.format(buf, indent + INDENT);
|
Newlines::No,
|
||||||
}
|
indent,
|
||||||
}
|
);
|
||||||
}
|
|
||||||
},
|
|
||||||
Value(def) => match def {
|
|
||||||
Annotation(loc_pattern, loc_annotation) => {
|
|
||||||
loc_pattern.format(buf, indent);
|
|
||||||
|
|
||||||
if loc_annotation.is_multiline() {
|
|
||||||
buf.push_str(" :");
|
|
||||||
|
|
||||||
let should_outdent = match loc_annotation.value {
|
|
||||||
TypeAnnotation::SpaceBefore(sub_def, spaces) => match sub_def {
|
|
||||||
TypeAnnotation::Record { .. } | TypeAnnotation::TagUnion { .. } => {
|
|
||||||
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
|
|
||||||
is_only_newlines && sub_def.is_multiline()
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
TypeAnnotation::Record { .. } | TypeAnnotation::TagUnion { .. } => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if should_outdent {
|
|
||||||
buf.spaces(1);
|
|
||||||
match loc_annotation.value {
|
|
||||||
TypeAnnotation::SpaceBefore(sub_def, _) => {
|
|
||||||
sub_def.format_with_options(
|
|
||||||
buf,
|
|
||||||
Parens::NotNeeded,
|
|
||||||
Newlines::No,
|
|
||||||
indent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
loc_annotation.format_with_options(
|
|
||||||
buf,
|
|
||||||
Parens::NotNeeded,
|
|
||||||
Newlines::No,
|
|
||||||
indent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
loc_annotation.format_with_options(
|
|
||||||
buf,
|
|
||||||
Parens::NotNeeded,
|
|
||||||
Newlines::Yes,
|
|
||||||
indent + INDENT,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf.spaces(1);
|
|
||||||
buf.push_str(":");
|
|
||||||
buf.spaces(1);
|
|
||||||
loc_annotation.format_with_options(
|
loc_annotation.format_with_options(
|
||||||
buf,
|
|
||||||
Parens::NotNeeded,
|
|
||||||
Newlines::No,
|
|
||||||
indent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Body(loc_pattern, loc_expr) => {
|
|
||||||
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
|
||||||
}
|
|
||||||
Expect(condition) => fmt_expect(buf, condition, self.is_multiline(), indent),
|
|
||||||
AnnotatedBody {
|
|
||||||
ann_pattern,
|
|
||||||
ann_type,
|
|
||||||
comment,
|
|
||||||
body_pattern,
|
|
||||||
body_expr,
|
|
||||||
} => {
|
|
||||||
let is_type_multiline = ann_type.is_multiline();
|
|
||||||
let is_type_function = matches!(
|
|
||||||
ann_type.value,
|
|
||||||
TypeAnnotation::Function(..)
|
|
||||||
| TypeAnnotation::SpaceBefore(TypeAnnotation::Function(..), ..)
|
|
||||||
| TypeAnnotation::SpaceAfter(TypeAnnotation::Function(..), ..)
|
|
||||||
);
|
|
||||||
|
|
||||||
let next_indent = if is_type_multiline {
|
|
||||||
indent + INDENT
|
|
||||||
} else {
|
|
||||||
indent
|
|
||||||
};
|
|
||||||
|
|
||||||
ann_pattern.format(buf, indent);
|
|
||||||
buf.push_str(" :");
|
|
||||||
|
|
||||||
if is_type_multiline && is_type_function {
|
|
||||||
ann_type.format_with_options(
|
|
||||||
buf,
|
buf,
|
||||||
Parens::NotNeeded,
|
Parens::NotNeeded,
|
||||||
Newlines::Yes,
|
Newlines::Yes,
|
||||||
next_indent,
|
indent + INDENT,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
buf.spaces(1);
|
|
||||||
ann_type.format(buf, indent);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if let Some(comment_str) = comment {
|
buf.spaces(1);
|
||||||
buf.push_str(" #");
|
buf.push_str(":");
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
buf.push_str(comment_str.trim());
|
loc_annotation.format_with_options(
|
||||||
}
|
buf,
|
||||||
|
Parens::NotNeeded,
|
||||||
buf.newline();
|
Newlines::No,
|
||||||
fmt_body(buf, &body_pattern.value, &body_expr.value, indent);
|
indent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
Body(loc_pattern, loc_expr) => {
|
||||||
|
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
||||||
|
}
|
||||||
|
Expect(condition) => fmt_expect(buf, condition, self.is_multiline(), indent),
|
||||||
|
AnnotatedBody {
|
||||||
|
ann_pattern,
|
||||||
|
ann_type,
|
||||||
|
comment,
|
||||||
|
body_pattern,
|
||||||
|
body_expr,
|
||||||
|
} => {
|
||||||
|
let is_type_multiline = ann_type.is_multiline();
|
||||||
|
let is_type_function = matches!(
|
||||||
|
ann_type.value,
|
||||||
|
TypeAnnotation::Function(..)
|
||||||
|
| TypeAnnotation::SpaceBefore(TypeAnnotation::Function(..), ..)
|
||||||
|
| TypeAnnotation::SpaceAfter(TypeAnnotation::Function(..), ..)
|
||||||
|
);
|
||||||
|
|
||||||
|
let next_indent = if is_type_multiline {
|
||||||
|
indent + INDENT
|
||||||
|
} else {
|
||||||
|
indent
|
||||||
|
};
|
||||||
|
|
||||||
|
ann_pattern.format(buf, indent);
|
||||||
|
buf.push_str(" :");
|
||||||
|
|
||||||
|
if is_type_multiline && is_type_function {
|
||||||
|
ann_type.format_with_options(
|
||||||
|
buf,
|
||||||
|
Parens::NotNeeded,
|
||||||
|
Newlines::Yes,
|
||||||
|
next_indent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
buf.spaces(1);
|
||||||
|
ann_type.format(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(comment_str) = comment {
|
||||||
|
buf.push_str(" #");
|
||||||
|
buf.spaces(1);
|
||||||
|
buf.push_str(comment_str.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.newline();
|
||||||
|
fmt_body(buf, &body_pattern.value, &body_expr.value, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Formattable for Def<'a> {
|
||||||
|
fn is_multiline(&self) -> bool {
|
||||||
|
use roc_parse::ast::Def::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Type(def) => def.is_multiline(),
|
||||||
|
Value(def) => def.is_multiline(),
|
||||||
|
SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => {
|
||||||
|
spaces.iter().any(|s| s.is_comment()) || sub_def.is_multiline()
|
||||||
|
}
|
||||||
|
NotYetImplemented(s) => todo!("{}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_with_options<'buf>(
|
||||||
|
&self,
|
||||||
|
buf: &mut Buf<'buf>,
|
||||||
|
parens: Parens,
|
||||||
|
newlines: Newlines,
|
||||||
|
indent: u16,
|
||||||
|
) {
|
||||||
|
use roc_parse::ast::Def::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Type(def) => def.format_with_options(buf, parens, newlines, indent),
|
||||||
|
Value(def) => def.format_with_options(buf, parens, newlines, indent),
|
||||||
|
|
||||||
SpaceBefore(sub_def, spaces) => {
|
SpaceBefore(sub_def, spaces) => {
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
|
@ -290,6 +352,22 @@ pub fn fmt_def<'a, 'buf>(buf: &mut Buf<'buf>, def: &Def<'a>, indent: u16) {
|
||||||
def.format(buf, indent);
|
def.format(buf, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fmt_value_def<'a, 'buf>(
|
||||||
|
buf: &mut Buf<'buf>,
|
||||||
|
def: &roc_parse::ast::ValueDef<'a>,
|
||||||
|
indent: u16,
|
||||||
|
) {
|
||||||
|
def.format(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmt_type_def<'a, 'buf>(buf: &mut Buf<'buf>, def: &roc_parse::ast::TypeDef<'a>, indent: u16) {
|
||||||
|
def.format(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmt_toplevel_defs<'a, 'buf>(buf: &mut Buf<'buf>, defs: &Defs<'a>, indent: u16) {
|
||||||
|
defs.format(buf, indent);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fmt_body<'a, 'buf>(
|
pub fn fmt_body<'a, 'buf>(
|
||||||
buf: &mut Buf<'buf>,
|
buf: &mut Buf<'buf>,
|
||||||
pattern: &'a Pattern<'a>,
|
pattern: &'a Pattern<'a>,
|
||||||
|
|
|
@ -116,7 +116,6 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
) {
|
) {
|
||||||
use self::Expr::*;
|
use self::Expr::*;
|
||||||
|
|
||||||
//dbg!(self);
|
|
||||||
let apply_needs_parens = parens == Parens::InApply;
|
let apply_needs_parens = parens == Parens::InApply;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -10,13 +10,12 @@ pub mod pattern;
|
||||||
pub mod spaces;
|
pub mod spaces;
|
||||||
|
|
||||||
use bumpalo::{collections::String, Bump};
|
use bumpalo::{collections::String, Bump};
|
||||||
use roc_parse::ast::{Def, Module};
|
use roc_parse::ast::Module;
|
||||||
use roc_region::all::Loc;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub struct Ast<'a> {
|
pub struct Ast<'a> {
|
||||||
pub module: Module<'a>,
|
pub module: Module<'a>,
|
||||||
pub defs: bumpalo::collections::vec::Vec<'a, Loc<Def<'a>>>,
|
pub defs: roc_parse::ast::Defs<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -184,10 +184,16 @@ impl<'a> RemoveSpaces<'a> for Ast<'a> {
|
||||||
Ast {
|
Ast {
|
||||||
module: self.module.remove_spaces(arena),
|
module: self.module.remove_spaces(arena),
|
||||||
defs: {
|
defs: {
|
||||||
let mut defs = Vec::with_capacity_in(self.defs.len(), arena);
|
let mut defs = self.defs.clone();
|
||||||
for d in &self.defs {
|
|
||||||
defs.push(d.remove_spaces(arena))
|
for type_def in defs.type_defs.iter_mut() {
|
||||||
|
*type_def = type_def.remove_spaces(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for value_def in defs.value_defs.iter_mut() {
|
||||||
|
*value_def = value_def.remove_spaces(arena);
|
||||||
|
}
|
||||||
|
|
||||||
defs
|
defs
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ extern crate roc_fmt;
|
||||||
mod test_fmt {
|
mod test_fmt {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_fmt::annotation::{Formattable, Newlines, Parens};
|
use roc_fmt::annotation::{Formattable, Newlines, Parens};
|
||||||
use roc_fmt::def::fmt_def;
|
use roc_fmt::def::fmt_toplevel_defs;
|
||||||
use roc_fmt::module::fmt_module;
|
use roc_fmt::module::fmt_module;
|
||||||
use roc_fmt::Buf;
|
use roc_fmt::Buf;
|
||||||
use roc_parse::ast::Module;
|
use roc_parse::ast::Module;
|
||||||
|
@ -88,11 +88,12 @@ mod test_fmt {
|
||||||
|
|
||||||
match module_defs().parse(arena, state) {
|
match module_defs().parse(arena, state) {
|
||||||
Ok((_, loc_defs, _)) => {
|
Ok((_, loc_defs, _)) => {
|
||||||
for loc_def in loc_defs {
|
fmt_toplevel_defs(buf, &loc_defs, 0);
|
||||||
fmt_def(buf, arena.alloc(loc_def.value), 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(error) => panic!("Unexpected parse failure when parsing this for defs formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, error)
|
Err(error) => panic!(
|
||||||
|
r"Unexpected parse failure when parsing this for defs formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n",
|
||||||
|
src, error
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,9 @@ use crate::file::LoadedModule;
|
||||||
use roc_can::scope::Scope;
|
use roc_can::scope::Scope;
|
||||||
use roc_module::ident::ModuleName;
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::symbol::IdentIds;
|
use roc_module::symbol::IdentIds;
|
||||||
|
use roc_parse::ast::AssignedField;
|
||||||
use roc_parse::ast::{self, ExtractSpaces, TypeHeader};
|
use roc_parse::ast::{self, ExtractSpaces, TypeHeader};
|
||||||
use roc_parse::ast::{AssignedField, Def};
|
|
||||||
use roc_parse::ast::{CommentOrNewline, TypeDef, ValueDef};
|
use roc_parse::ast::{CommentOrNewline, TypeDef, ValueDef};
|
||||||
use roc_region::all::Loc;
|
|
||||||
|
|
||||||
// Documentation generation requirements
|
// Documentation generation requirements
|
||||||
|
|
||||||
|
@ -97,22 +96,12 @@ pub struct Tag {
|
||||||
pub values: Vec<TypeAnnotation>,
|
pub values: Vec<TypeAnnotation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_module_docs<'a>(
|
pub fn generate_module_docs(
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
module_name: ModuleName,
|
module_name: ModuleName,
|
||||||
parsed_defs: &'a [Loc<ast::Def<'a>>],
|
parsed_defs: &roc_parse::ast::Defs,
|
||||||
) -> ModuleDocumentation {
|
) -> ModuleDocumentation {
|
||||||
let (entries, _) =
|
let entries = generate_entry_docs(&scope.locals.ident_ids, parsed_defs);
|
||||||
parsed_defs
|
|
||||||
.iter()
|
|
||||||
.fold((vec![], None), |(acc, maybe_comments_after), def| {
|
|
||||||
generate_entry_doc(
|
|
||||||
&scope.locals.ident_ids,
|
|
||||||
acc,
|
|
||||||
maybe_comments_after,
|
|
||||||
&def.value,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
ModuleDocumentation {
|
ModuleDocumentation {
|
||||||
name: module_name.as_str().to_string(),
|
name: module_name.as_str().to_string(),
|
||||||
|
@ -148,176 +137,152 @@ fn detached_docs_from_comments_and_new_lines<'a>(
|
||||||
detached_docs
|
detached_docs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_entry_doc<'a>(
|
fn generate_entry_docs<'a>(
|
||||||
ident_ids: &'a IdentIds,
|
ident_ids: &'a IdentIds,
|
||||||
mut acc: Vec<DocEntry>,
|
defs: &roc_parse::ast::Defs<'a>,
|
||||||
before_comments_or_new_lines: Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>,
|
) -> Vec<DocEntry> {
|
||||||
def: &'a ast::Def<'a>,
|
|
||||||
) -> (
|
|
||||||
Vec<DocEntry>,
|
|
||||||
Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>,
|
|
||||||
) {
|
|
||||||
use roc_parse::ast::Pattern;
|
use roc_parse::ast::Pattern;
|
||||||
|
|
||||||
match def {
|
let mut acc = Vec::with_capacity(defs.tags.len());
|
||||||
Def::SpaceBefore(sub_def, comments_or_new_lines) => {
|
let mut before_comments_or_new_lines = None;
|
||||||
// Comments before a definition are attached to the current definition
|
|
||||||
|
|
||||||
for detached_doc in detached_docs_from_comments_and_new_lines(comments_or_new_lines) {
|
for (index, either_index) in defs.tags.iter().enumerate() {
|
||||||
acc.push(DetachedDoc(detached_doc));
|
let spaces_before = &defs.spaces[defs.space_before[index].indices()];
|
||||||
}
|
|
||||||
|
|
||||||
generate_entry_doc(ident_ids, acc, Some(comments_or_new_lines), sub_def)
|
for detached_doc in detached_docs_from_comments_and_new_lines(spaces_before) {
|
||||||
|
acc.push(DetachedDoc(detached_doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
Def::SpaceAfter(sub_def, comments_or_new_lines) => {
|
match either_index.split() {
|
||||||
let (new_acc, _) =
|
Err(value_index) => match &defs.value_defs[value_index.index()] {
|
||||||
// If there are comments before, attach to this definition
|
ValueDef::Annotation(loc_pattern, loc_ann) => {
|
||||||
generate_entry_doc(ident_ids, acc, before_comments_or_new_lines, sub_def);
|
if let Pattern::Identifier(identifier) = loc_pattern.value {
|
||||||
|
// Check if the definition is exposed
|
||||||
// Comments after a definition are attached to the next definition
|
if ident_ids.get_id(&identifier.into()).is_some() {
|
||||||
(new_acc, Some(comments_or_new_lines))
|
let name = identifier.to_string();
|
||||||
}
|
let doc_def = DocDef {
|
||||||
|
name,
|
||||||
Def::Value(def) => match def {
|
type_annotation: type_to_docs(false, loc_ann.value),
|
||||||
ValueDef::Annotation(loc_pattern, loc_ann) => match loc_pattern.value {
|
type_vars: Vec::new(),
|
||||||
Pattern::Identifier(identifier) => {
|
docs: before_comments_or_new_lines
|
||||||
// Check if the definition is exposed
|
.and_then(comments_or_new_lines_to_docs),
|
||||||
if ident_ids.get_id(&identifier.into()).is_some() {
|
};
|
||||||
let name = identifier.to_string();
|
acc.push(DocEntry::DocDef(doc_def));
|
||||||
let doc_def = DocDef {
|
|
||||||
name,
|
|
||||||
type_annotation: type_to_docs(false, loc_ann.value),
|
|
||||||
type_vars: Vec::new(),
|
|
||||||
docs: before_comments_or_new_lines
|
|
||||||
.and_then(comments_or_new_lines_to_docs),
|
|
||||||
};
|
|
||||||
acc.push(DocEntry::DocDef(doc_def));
|
|
||||||
}
|
|
||||||
(acc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (acc, None),
|
|
||||||
},
|
|
||||||
|
|
||||||
ValueDef::AnnotatedBody {
|
|
||||||
ann_pattern,
|
|
||||||
ann_type,
|
|
||||||
..
|
|
||||||
} => match ann_pattern.value {
|
|
||||||
Pattern::Identifier(identifier) => {
|
|
||||||
// Check if the definition is exposed
|
|
||||||
if ident_ids.get_id(&identifier.into()).is_some() {
|
|
||||||
let doc_def = DocDef {
|
|
||||||
name: identifier.to_string(),
|
|
||||||
type_annotation: type_to_docs(false, ann_type.value),
|
|
||||||
type_vars: Vec::new(),
|
|
||||||
docs: before_comments_or_new_lines
|
|
||||||
.and_then(comments_or_new_lines_to_docs),
|
|
||||||
};
|
|
||||||
acc.push(DocEntry::DocDef(doc_def));
|
|
||||||
}
|
|
||||||
(acc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (acc, None),
|
|
||||||
},
|
|
||||||
|
|
||||||
ValueDef::Body(_, _) => (acc, None),
|
|
||||||
|
|
||||||
ValueDef::Expect(c) => todo!("documentation for tests {:?}", c),
|
|
||||||
},
|
|
||||||
|
|
||||||
Def::Type(def) => match def {
|
|
||||||
TypeDef::Alias {
|
|
||||||
header: TypeHeader { name, vars },
|
|
||||||
ann,
|
|
||||||
} => {
|
|
||||||
let mut type_vars = Vec::new();
|
|
||||||
|
|
||||||
for var in vars.iter() {
|
|
||||||
if let Pattern::Identifier(ident_name) = var.value {
|
|
||||||
type_vars.push(ident_name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let doc_def = DocDef {
|
|
||||||
name: name.value.to_string(),
|
|
||||||
type_annotation: type_to_docs(false, ann.value),
|
|
||||||
type_vars,
|
|
||||||
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
|
||||||
};
|
|
||||||
acc.push(DocEntry::DocDef(doc_def));
|
|
||||||
|
|
||||||
(acc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeDef::Opaque {
|
|
||||||
header: TypeHeader { name, vars },
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let mut type_vars = Vec::new();
|
|
||||||
|
|
||||||
for var in vars.iter() {
|
|
||||||
if let Pattern::Identifier(ident_name) = var.value {
|
|
||||||
type_vars.push(ident_name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let doc_def = DocDef {
|
|
||||||
name: name.value.to_string(),
|
|
||||||
type_annotation: TypeAnnotation::NoTypeAnn,
|
|
||||||
type_vars,
|
|
||||||
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
|
||||||
};
|
|
||||||
acc.push(DocEntry::DocDef(doc_def));
|
|
||||||
|
|
||||||
(acc, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeDef::Ability {
|
|
||||||
header: TypeHeader { name, vars },
|
|
||||||
members,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let mut type_vars = Vec::new();
|
|
||||||
|
|
||||||
for var in vars.iter() {
|
|
||||||
if let Pattern::Identifier(ident_name) = var.value {
|
|
||||||
type_vars.push(ident_name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let members = members
|
|
||||||
.iter()
|
|
||||||
.map(|mem| {
|
|
||||||
let extracted = mem.name.value.extract_spaces();
|
|
||||||
let (type_annotation, able_variables) =
|
|
||||||
ability_member_type_to_docs(mem.typ.value);
|
|
||||||
|
|
||||||
AbilityMember {
|
|
||||||
name: extracted.item.to_string(),
|
|
||||||
type_annotation,
|
|
||||||
able_variables,
|
|
||||||
docs: comments_or_new_lines_to_docs(extracted.before),
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect();
|
}
|
||||||
|
|
||||||
let doc_def = DocDef {
|
ValueDef::AnnotatedBody {
|
||||||
name: name.value.to_string(),
|
ann_pattern,
|
||||||
type_annotation: TypeAnnotation::Ability { members },
|
ann_type,
|
||||||
type_vars,
|
..
|
||||||
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
} => {
|
||||||
};
|
if let Pattern::Identifier(identifier) = ann_pattern.value {
|
||||||
acc.push(DocEntry::DocDef(doc_def));
|
// Check if the definition is exposed
|
||||||
|
if ident_ids.get_id(&identifier.into()).is_some() {
|
||||||
|
let doc_def = DocDef {
|
||||||
|
name: identifier.to_string(),
|
||||||
|
type_annotation: type_to_docs(false, ann_type.value),
|
||||||
|
type_vars: Vec::new(),
|
||||||
|
docs: before_comments_or_new_lines
|
||||||
|
.and_then(comments_or_new_lines_to_docs),
|
||||||
|
};
|
||||||
|
acc.push(DocEntry::DocDef(doc_def));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(acc, None)
|
ValueDef::Body(_, _) => (),
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Def::NotYetImplemented(s) => todo!("{}", s),
|
ValueDef::Expect(c) => todo!("documentation for tests {:?}", c),
|
||||||
|
},
|
||||||
|
Ok(type_index) => match &defs.type_defs[type_index.index()] {
|
||||||
|
TypeDef::Alias {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
ann,
|
||||||
|
} => {
|
||||||
|
let mut type_vars = Vec::new();
|
||||||
|
|
||||||
|
for var in vars.iter() {
|
||||||
|
if let Pattern::Identifier(ident_name) = var.value {
|
||||||
|
type_vars.push(ident_name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let doc_def = DocDef {
|
||||||
|
name: name.value.to_string(),
|
||||||
|
type_annotation: type_to_docs(false, ann.value),
|
||||||
|
type_vars,
|
||||||
|
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
||||||
|
};
|
||||||
|
acc.push(DocEntry::DocDef(doc_def));
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDef::Opaque {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut type_vars = Vec::new();
|
||||||
|
|
||||||
|
for var in vars.iter() {
|
||||||
|
if let Pattern::Identifier(ident_name) = var.value {
|
||||||
|
type_vars.push(ident_name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let doc_def = DocDef {
|
||||||
|
name: name.value.to_string(),
|
||||||
|
type_annotation: TypeAnnotation::NoTypeAnn,
|
||||||
|
type_vars,
|
||||||
|
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
||||||
|
};
|
||||||
|
acc.push(DocEntry::DocDef(doc_def));
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDef::Ability {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
members,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut type_vars = Vec::new();
|
||||||
|
|
||||||
|
for var in vars.iter() {
|
||||||
|
if let Pattern::Identifier(ident_name) = var.value {
|
||||||
|
type_vars.push(ident_name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let members = members
|
||||||
|
.iter()
|
||||||
|
.map(|mem| {
|
||||||
|
let extracted = mem.name.value.extract_spaces();
|
||||||
|
let (type_annotation, able_variables) =
|
||||||
|
ability_member_type_to_docs(mem.typ.value);
|
||||||
|
|
||||||
|
AbilityMember {
|
||||||
|
name: extracted.item.to_string(),
|
||||||
|
type_annotation,
|
||||||
|
able_variables,
|
||||||
|
docs: comments_or_new_lines_to_docs(extracted.before),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let doc_def = DocDef {
|
||||||
|
name: name.value.to_string(),
|
||||||
|
type_annotation: TypeAnnotation::Ability { members },
|
||||||
|
type_vars,
|
||||||
|
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
||||||
|
};
|
||||||
|
acc.push(DocEntry::DocDef(doc_def));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
before_comments_or_new_lines = Some(&defs.spaces[defs.space_after[index].indices()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) -> TypeAnnotation {
|
fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) -> TypeAnnotation {
|
||||||
|
|
|
@ -33,7 +33,7 @@ use roc_mono::ir::{
|
||||||
UpdateModeIds,
|
UpdateModeIds,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||||
use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
use roc_parse::ast::{self, Defs, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
||||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||||
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
|
@ -616,7 +616,7 @@ struct ParsedModule<'a> {
|
||||||
imported_modules: MutMap<ModuleId, Region>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
parsed_defs: &'a [Loc<roc_parse::ast::Def<'a>>],
|
parsed_defs: Defs<'a>,
|
||||||
module_name: ModuleNameEnum<'a>,
|
module_name: ModuleNameEnum<'a>,
|
||||||
symbols_from_requires: Vec<(Loc<Symbol>, Loc<TypeAnnotation<'a>>)>,
|
symbols_from_requires: Vec<(Loc<Symbol>, Loc<TypeAnnotation<'a>>)>,
|
||||||
header_for: HeaderFor<'a>,
|
header_for: HeaderFor<'a>,
|
||||||
|
@ -3884,6 +3884,9 @@ fn canonicalize_and_constrain<'a>(
|
||||||
// _before has an underscore because it's unused in --release builds
|
// _before has an underscore because it's unused in --release builds
|
||||||
let _before = roc_types::types::get_type_clone_count();
|
let _before = roc_types::types::get_type_clone_count();
|
||||||
|
|
||||||
|
let parsed_defs_for_docs = parsed_defs.clone();
|
||||||
|
let parsed_defs = arena.alloc(parsed_defs);
|
||||||
|
|
||||||
let mut var_store = VarStore::default();
|
let mut var_store = VarStore::default();
|
||||||
let module_output = canonicalize_module_defs(
|
let module_output = canonicalize_module_defs(
|
||||||
arena,
|
arena,
|
||||||
|
@ -3925,7 +3928,7 @@ fn canonicalize_and_constrain<'a>(
|
||||||
let docs = crate::docs::generate_module_docs(
|
let docs = crate::docs::generate_module_docs(
|
||||||
module_output.scope.clone(),
|
module_output.scope.clone(),
|
||||||
name.as_str().into(),
|
name.as_str().into(),
|
||||||
parsed_defs,
|
&parsed_defs_for_docs,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(docs)
|
Some(docs)
|
||||||
|
@ -4025,8 +4028,6 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed_defs = parsed_defs.into_bump_slice();
|
|
||||||
|
|
||||||
// Record the parse end time once, to avoid checking the time a second time
|
// Record the parse end time once, to avoid checking the time a second time
|
||||||
// immediately afterward (for the beginning of canonicalization).
|
// immediately afterward (for the beginning of canonicalization).
|
||||||
let parse_end = SystemTime::now();
|
let parse_end = SystemTime::now();
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::header::{AppHeader, HostedHeader, InterfaceHeader, PlatformHeader};
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use bumpalo::collections::{String, Vec};
|
use bumpalo::collections::{String, Vec};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use roc_collections::soa::{EitherIndex, Index, Slice};
|
||||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
|
@ -333,6 +334,89 @@ pub enum ValueDef<'a> {
|
||||||
Expect(&'a Loc<Expr<'a>>),
|
Expect(&'a Loc<Expr<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
pub struct Defs<'a> {
|
||||||
|
pub tags: std::vec::Vec<EitherIndex<TypeDef<'a>, ValueDef<'a>>>,
|
||||||
|
pub regions: std::vec::Vec<Region>,
|
||||||
|
pub space_before: std::vec::Vec<Slice<CommentOrNewline<'a>>>,
|
||||||
|
pub space_after: std::vec::Vec<Slice<CommentOrNewline<'a>>>,
|
||||||
|
pub spaces: std::vec::Vec<CommentOrNewline<'a>>,
|
||||||
|
pub type_defs: std::vec::Vec<TypeDef<'a>>,
|
||||||
|
pub value_defs: std::vec::Vec<ValueDef<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Defs<'a> {
|
||||||
|
pub fn defs(&self) -> impl Iterator<Item = Result<&TypeDef<'a>, &ValueDef<'a>>> {
|
||||||
|
self.tags.iter().map(|tag| match tag.split() {
|
||||||
|
Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
|
||||||
|
Err(value_index) => Err(&self.value_defs[value_index.index()]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last(&self) -> Option<Result<&TypeDef<'a>, &ValueDef<'a>>> {
|
||||||
|
self.tags.last().map(|tag| match tag.split() {
|
||||||
|
Ok(type_index) => Ok(&self.type_defs[type_index.index()]),
|
||||||
|
Err(value_index) => Err(&self.value_defs[value_index.index()]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NOTE assumes the def itself is pushed already!
|
||||||
|
fn push_def_help(
|
||||||
|
&mut self,
|
||||||
|
tag: EitherIndex<TypeDef<'a>, ValueDef<'a>>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
self.tags.push(tag);
|
||||||
|
|
||||||
|
self.regions.push(region);
|
||||||
|
|
||||||
|
let before = Slice::extend_new(&mut self.spaces, spaces_before.iter().copied());
|
||||||
|
self.space_before.push(before);
|
||||||
|
|
||||||
|
let after = Slice::extend_new(&mut self.spaces, spaces_after.iter().copied());
|
||||||
|
self.space_after.push(after);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_value_def(
|
||||||
|
&mut self,
|
||||||
|
value_def: ValueDef<'a>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
let value_def_index = Index::push_new(&mut self.value_defs, value_def);
|
||||||
|
let tag = EitherIndex::from_right(value_def_index);
|
||||||
|
self.push_def_help(tag, region, spaces_before, spaces_after)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_with_value_def(
|
||||||
|
&mut self,
|
||||||
|
index: usize,
|
||||||
|
value_def: ValueDef<'a>,
|
||||||
|
region: Region,
|
||||||
|
) {
|
||||||
|
let value_def_index = Index::push_new(&mut self.value_defs, value_def);
|
||||||
|
let tag = EitherIndex::from_right(value_def_index);
|
||||||
|
|
||||||
|
self.tags[index] = tag;
|
||||||
|
self.regions[index] = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_type_def(
|
||||||
|
&mut self,
|
||||||
|
type_def: TypeDef<'a>,
|
||||||
|
region: Region,
|
||||||
|
spaces_before: &[CommentOrNewline<'a>],
|
||||||
|
spaces_after: &[CommentOrNewline<'a>],
|
||||||
|
) {
|
||||||
|
let type_def_index = Index::push_new(&mut self.type_defs, type_def);
|
||||||
|
let tag = EitherIndex::from_left(type_def_index);
|
||||||
|
self.push_def_help(tag, region, spaces_before, spaces_after)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Def<'a> {
|
pub enum Def<'a> {
|
||||||
Type(TypeDef<'a>),
|
Type(TypeDef<'a>),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
AssignedField, Collection, CommentOrNewline, Def, Derived, Expr, ExtractSpaces, Has, Pattern,
|
AssignedField, Collection, CommentOrNewline, Def, Defs, Derived, Expr, ExtractSpaces, Has,
|
||||||
Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
Pattern, Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||||
|
@ -17,6 +17,7 @@ use crate::state::State;
|
||||||
use crate::type_annotation;
|
use crate::type_annotation;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use roc_collections::soa::Slice;
|
||||||
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
|
@ -811,6 +812,337 @@ struct DefState<'a> {
|
||||||
spaces_after: &'a [CommentOrNewline<'a>],
|
spaces_after: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_toplevel_defs_end<'a>(
|
||||||
|
_options: ExprParseOptions,
|
||||||
|
start_column: u32,
|
||||||
|
mut defs: Defs<'a>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
) -> ParseResult<'a, Defs<'a>, EExpr<'a>> {
|
||||||
|
let min_indent = start_column;
|
||||||
|
|
||||||
|
let mut global_state = state;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let state = global_state;
|
||||||
|
let initial = state.clone();
|
||||||
|
|
||||||
|
let mut spaces_before_current = &[] as &[_];
|
||||||
|
|
||||||
|
let state = match space0_e(min_indent, EExpr::IndentStart).parse(arena, state) {
|
||||||
|
Err((MadeProgress, _, s)) => {
|
||||||
|
return Err((MadeProgress, EExpr::DefMissingFinalExpr(s.pos()), s));
|
||||||
|
}
|
||||||
|
Ok((_, spaces, state)) => {
|
||||||
|
spaces_before_current = spaces;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
Err((NoProgress, _, state)) => state,
|
||||||
|
};
|
||||||
|
|
||||||
|
let start = state.pos();
|
||||||
|
|
||||||
|
match space0_after_e(
|
||||||
|
crate::pattern::loc_pattern_help(min_indent),
|
||||||
|
min_indent,
|
||||||
|
EPattern::IndentEnd,
|
||||||
|
)
|
||||||
|
.parse(arena, state.clone())
|
||||||
|
{
|
||||||
|
Err((NoProgress, _, _)) => {
|
||||||
|
match crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect)
|
||||||
|
.parse(arena, state)
|
||||||
|
{
|
||||||
|
Err((_, _, _)) => {
|
||||||
|
// a hacky way to get expression-based error messages. TODO fix this
|
||||||
|
return Ok((NoProgress, defs, initial));
|
||||||
|
}
|
||||||
|
Ok((_, _, state)) => {
|
||||||
|
let parse_def_expr = space0_before_e(
|
||||||
|
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||||
|
min_indent,
|
||||||
|
EExpr::IndentEnd,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||||
|
|
||||||
|
let end = loc_def_expr.region.end();
|
||||||
|
let region = Region::new(start, end);
|
||||||
|
|
||||||
|
let value_def = ValueDef::Expect(arena.alloc(loc_def_expr));
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
|
||||||
|
global_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((MadeProgress, _, _)) => {
|
||||||
|
// a hacky way to get expression-based error messages. TODO fix this
|
||||||
|
return Ok((NoProgress, defs, initial));
|
||||||
|
}
|
||||||
|
Ok((_, loc_pattern, state)) => {
|
||||||
|
// First let's check whether this is an ability definition.
|
||||||
|
let opt_tag_and_args: Option<(&str, Region, &[Loc<Pattern>])> =
|
||||||
|
match loc_pattern.value {
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
region,
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
) => Some((name, *region, args)),
|
||||||
|
Pattern::Tag(name) => Some((name, loc_pattern.region, &[])),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((name, name_region, args)) = opt_tag_and_args {
|
||||||
|
if let Ok((_, loc_has, state)) =
|
||||||
|
loc_has_parser(min_indent).parse(arena, state.clone())
|
||||||
|
{
|
||||||
|
let (_, (type_def, def_region), state) = finish_parsing_ability_def_help(
|
||||||
|
start_column,
|
||||||
|
Loc::at(name_region, name),
|
||||||
|
args,
|
||||||
|
loc_has,
|
||||||
|
arena,
|
||||||
|
state,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, def_region, spaces_before_current, &[]);
|
||||||
|
|
||||||
|
global_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, this is a def or alias.
|
||||||
|
match operator().parse(arena, state) {
|
||||||
|
Ok((_, BinOp::Assignment, state)) => {
|
||||||
|
let parse_def_expr = space0_before_e(
|
||||||
|
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||||
|
min_indent,
|
||||||
|
EExpr::IndentEnd,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let region =
|
||||||
|
Region::span_across(&loc_pattern.region, &loc_def_expr.region);
|
||||||
|
|
||||||
|
if spaces_before_current.len() <= 1 {
|
||||||
|
let comment = match spaces_before_current.get(0) {
|
||||||
|
Some(CommentOrNewline::LineComment(s)) => Some(*s),
|
||||||
|
Some(CommentOrNewline::DocComment(s)) => Some(*s),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match defs.last() {
|
||||||
|
Some(Err(ValueDef::Annotation(ann_pattern, ann_type))) => {
|
||||||
|
// join this body with the preceding annotation
|
||||||
|
|
||||||
|
let value_def = ValueDef::AnnotatedBody {
|
||||||
|
ann_pattern: arena.alloc(*ann_pattern),
|
||||||
|
ann_type: arena.alloc(*ann_type),
|
||||||
|
comment,
|
||||||
|
body_pattern: arena.alloc(loc_pattern),
|
||||||
|
body_expr: &*arena.alloc(loc_def_expr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let region =
|
||||||
|
Region::span_across(&ann_pattern.region, ®ion);
|
||||||
|
|
||||||
|
defs.replace_with_value_def(
|
||||||
|
defs.tags.len() - 1,
|
||||||
|
value_def,
|
||||||
|
region,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Some(Ok(TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
})) => {
|
||||||
|
// This is a case like
|
||||||
|
// UserId x : [UserId Int]
|
||||||
|
// UserId x = UserId 42
|
||||||
|
// We optimistically parsed the first line as an alias; we now turn it
|
||||||
|
// into an annotation.
|
||||||
|
|
||||||
|
let loc_name =
|
||||||
|
arena.alloc(header.name.map(|x| Pattern::Tag(x)));
|
||||||
|
let ann_pattern = Pattern::Apply(loc_name, header.vars);
|
||||||
|
|
||||||
|
let vars_region = Region::across_all(
|
||||||
|
header.vars.iter().map(|v| &v.region),
|
||||||
|
);
|
||||||
|
let region_ann_pattern =
|
||||||
|
Region::span_across(&loc_name.region, &vars_region);
|
||||||
|
let loc_ann_pattern =
|
||||||
|
Loc::at(region_ann_pattern, ann_pattern);
|
||||||
|
|
||||||
|
let value_def = ValueDef::AnnotatedBody {
|
||||||
|
ann_pattern: arena.alloc(loc_ann_pattern),
|
||||||
|
ann_type: arena.alloc(*ann_type),
|
||||||
|
comment,
|
||||||
|
body_pattern: arena.alloc(loc_pattern),
|
||||||
|
body_expr: &*arena.alloc(loc_def_expr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let region =
|
||||||
|
Region::span_across(&header.name.region, ®ion);
|
||||||
|
|
||||||
|
defs.replace_with_value_def(
|
||||||
|
defs.tags.len() - 1,
|
||||||
|
value_def,
|
||||||
|
region,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
let value_def = ValueDef::Body(
|
||||||
|
arena.alloc(loc_pattern),
|
||||||
|
&*arena.alloc(loc_def_expr),
|
||||||
|
);
|
||||||
|
|
||||||
|
defs.push_value_def(
|
||||||
|
value_def,
|
||||||
|
region,
|
||||||
|
spaces_before_current,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
let value_def = ValueDef::Body(
|
||||||
|
arena.alloc(loc_pattern),
|
||||||
|
&*arena.alloc(loc_def_expr),
|
||||||
|
);
|
||||||
|
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
global_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Ok((_, BinOp::IsAliasType, state)) => {
|
||||||
|
let (_, ann_type, state) =
|
||||||
|
alias_signature_with_space_before(min_indent + 1)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let region = Region::span_across(&loc_pattern.region, &ann_type.region);
|
||||||
|
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
match &loc_pattern.value {
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
alias_arguments,
|
||||||
|
) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: alias_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
Pattern::Tag(name) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let pattern_arguments: &'a [Loc<Pattern<'a>>] = &[];
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: pattern_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let value_def = ValueDef::Annotation(loc_pattern, ann_type);
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
global_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Ok((_, BinOp::IsOpaqueType, state)) => {
|
||||||
|
let (_, (signature, derived), state) =
|
||||||
|
opaque_signature_with_space_before(min_indent + 1)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let region = Region::span_across(&loc_pattern.region, &signature.region);
|
||||||
|
|
||||||
|
// the previous and current def can't be joined up
|
||||||
|
match &loc_pattern.value {
|
||||||
|
Pattern::Apply(
|
||||||
|
Loc {
|
||||||
|
value: Pattern::Tag(name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
alias_arguments,
|
||||||
|
) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: alias_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Opaque {
|
||||||
|
header,
|
||||||
|
typ: signature,
|
||||||
|
derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
Pattern::Tag(name) => {
|
||||||
|
let name = Loc::at(loc_pattern.region, *name);
|
||||||
|
let pattern_arguments: &'a [Loc<Pattern<'a>>] = &[];
|
||||||
|
let header = TypeHeader {
|
||||||
|
name,
|
||||||
|
vars: pattern_arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_def = TypeDef::Opaque {
|
||||||
|
header,
|
||||||
|
typ: signature,
|
||||||
|
derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
defs.push_type_def(type_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let value_def = ValueDef::Annotation(loc_pattern, signature);
|
||||||
|
defs.push_value_def(value_def, region, spaces_before_current, &[]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
global_state = state;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => return Ok((MadeProgress, defs, initial)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_defs_end<'a>(
|
fn parse_defs_end<'a>(
|
||||||
options: ExprParseOptions,
|
options: ExprParseOptions,
|
||||||
start_column: u32,
|
start_column: u32,
|
||||||
|
@ -1309,6 +1641,32 @@ fn finish_parsing_ability_def<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
) -> ParseResult<'a, &'a Loc<Def<'a>>, EExpr<'a>> {
|
) -> ParseResult<'a, &'a Loc<Def<'a>>, EExpr<'a>> {
|
||||||
|
let (_, (type_def, def_region), state) =
|
||||||
|
finish_parsing_ability_def_help(start_column, name, args, loc_has, arena, state)?;
|
||||||
|
|
||||||
|
let def = Def::Type(type_def);
|
||||||
|
|
||||||
|
let loc_def = &*(if spaces_before.is_empty() {
|
||||||
|
arena.alloc(Loc::at(def_region, def))
|
||||||
|
} else {
|
||||||
|
arena.alloc(
|
||||||
|
arena
|
||||||
|
.alloc(def)
|
||||||
|
.with_spaces_before(spaces_before, def_region),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok((MadeProgress, loc_def, state))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_parsing_ability_def_help<'a>(
|
||||||
|
start_column: u32,
|
||||||
|
name: Loc<&'a str>,
|
||||||
|
args: &'a [Loc<Pattern<'a>>],
|
||||||
|
loc_has: Loc<Has<'a>>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
) -> ParseResult<'a, (TypeDef<'a>, Region), EExpr<'a>> {
|
||||||
let mut demands = Vec::with_capacity_in(2, arena);
|
let mut demands = Vec::with_capacity_in(2, arena);
|
||||||
|
|
||||||
let min_indent_for_demand = start_column + 1;
|
let min_indent_for_demand = start_column + 1;
|
||||||
|
@ -1347,23 +1705,13 @@ fn finish_parsing_ability_def<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
||||||
let def = Def::Type(TypeDef::Ability {
|
let type_def = TypeDef::Ability {
|
||||||
header: TypeHeader { name, vars: args },
|
header: TypeHeader { name, vars: args },
|
||||||
loc_has,
|
loc_has,
|
||||||
members: demands.into_bump_slice(),
|
members: demands.into_bump_slice(),
|
||||||
});
|
};
|
||||||
|
|
||||||
let loc_def = &*(if spaces_before.is_empty() {
|
Ok((MadeProgress, (type_def, def_region), state))
|
||||||
arena.alloc(Loc::at(def_region, def))
|
|
||||||
} else {
|
|
||||||
arena.alloc(
|
|
||||||
arena
|
|
||||||
.alloc(def)
|
|
||||||
.with_spaces_before(spaces_before, def_region),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok((MadeProgress, loc_def, state))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_parsing_ability<'a>(
|
fn finish_parsing_ability<'a>(
|
||||||
|
@ -1960,6 +2308,43 @@ fn assigned_expr_field_to_pattern_help<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toplevel_defs<'a>(min_indent: u32) -> impl Parser<'a, Defs<'a>, EExpr<'a>> {
|
||||||
|
move |arena, state: State<'a>| {
|
||||||
|
let (_, initial_space, state) =
|
||||||
|
space0_e(min_indent, EExpr::IndentEnd).parse(arena, state)?;
|
||||||
|
|
||||||
|
let start_column = state.column();
|
||||||
|
|
||||||
|
let options = ExprParseOptions {
|
||||||
|
accept_multi_backpassing: false,
|
||||||
|
check_for_arrow: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output = Defs::default();
|
||||||
|
let before = Slice::extend_new(&mut output.spaces, initial_space.iter().copied());
|
||||||
|
|
||||||
|
let (_, mut output, state) =
|
||||||
|
parse_toplevel_defs_end(options, start_column, output, arena, state)?;
|
||||||
|
|
||||||
|
let (_, final_space, state) =
|
||||||
|
space0_e(start_column, EExpr::IndentEnd).parse(arena, state)?;
|
||||||
|
|
||||||
|
if !output.tags.is_empty() {
|
||||||
|
// add surrounding whitespace
|
||||||
|
let after = Slice::extend_new(&mut output.spaces, final_space.iter().copied());
|
||||||
|
|
||||||
|
debug_assert!(output.space_before[0].is_empty());
|
||||||
|
output.space_before[0] = before;
|
||||||
|
|
||||||
|
let last = output.tags.len() - 1;
|
||||||
|
debug_assert!(output.space_after[last].is_empty() || after.is_empty());
|
||||||
|
output.space_after[last] = after;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((MadeProgress, output, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn defs<'a>(min_indent: u32) -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, EExpr<'a>> {
|
pub fn defs<'a>(min_indent: u32) -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, EExpr<'a>> {
|
||||||
move |arena, state: State<'a>| {
|
move |arena, state: State<'a>| {
|
||||||
let def_state = DefState {
|
let def_state = DefState {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
|
use crate::ast::{Collection, CommentOrNewline, Def, Defs, Module, Spaced};
|
||||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::header::{
|
use crate::header::{
|
||||||
package_entry, package_name, AppHeader, ExposedName, HostedHeader, ImportsEntry,
|
package_entry, package_name, AppHeader, ExposedName, HostedHeader, ImportsEntry,
|
||||||
|
@ -28,7 +28,19 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, SyntaxError<'a>> {
|
pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> {
|
||||||
|
let min_indent = 0;
|
||||||
|
skip_second!(
|
||||||
|
specialize_region(
|
||||||
|
|e, r| SyntaxError::Expr(e, r.start()),
|
||||||
|
crate::expr::toplevel_defs(min_indent),
|
||||||
|
),
|
||||||
|
end_of_file()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn module_defs_help<'a>() -> impl Parser<'a, Vec<'a, Loc<Def<'a>>>, SyntaxError<'a>> {
|
||||||
// force that we parse until the end of the input
|
// force that we parse until the end of the input
|
||||||
let min_indent = 0;
|
let min_indent = 0;
|
||||||
skip_second!(
|
skip_second!(
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::module::module_defs;
|
use crate::ast::Def;
|
||||||
|
use crate::module::module_defs_help;
|
||||||
// use crate::module::module_defs;
|
// use crate::module::module_defs;
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
use crate::parser::SourceError;
|
use crate::parser::SourceError;
|
||||||
use crate::parser::SyntaxError;
|
use crate::parser::SyntaxError;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use bumpalo::collections::Vec as BumpVec;
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
use roc_region::all::Position;
|
use roc_region::all::Position;
|
||||||
|
@ -35,10 +35,10 @@ pub fn parse_loc_with<'a>(
|
||||||
pub fn parse_defs_with<'a>(
|
pub fn parse_defs_with<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
) -> Result<BumpVec<'a, Loc<ast::Def<'a>>>, SyntaxError<'a>> {
|
) -> Result<bumpalo::collections::Vec<'a, Loc<Def<'a>>>, SyntaxError<'a>> {
|
||||||
let state = State::new(input.trim().as_bytes());
|
let state = State::new(input.trim().as_bytes());
|
||||||
|
|
||||||
match module_defs().parse(arena, state) {
|
match module_defs_help().parse(arena, state) {
|
||||||
Ok(tuple) => Ok(tuple.1),
|
Ok(tuple) => Ok(tuple.1),
|
||||||
Err(tuple) => Err(tuple.1),
|
Err(tuple) => Err(tuple.1),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
[
|
Defs {
|
||||||
@0-7 SpaceAfter(
|
tags: [
|
||||||
SpaceBefore(
|
Index(2147483648),
|
||||||
Value(
|
],
|
||||||
Body(
|
regions: [
|
||||||
@0-3 Identifier(
|
@0-7,
|
||||||
"foo",
|
],
|
||||||
),
|
space_before: [
|
||||||
@6-7 Num(
|
Slice(start = 0, length = 0),
|
||||||
"1",
|
],
|
||||||
),
|
space_after: [
|
||||||
),
|
Slice(start = 0, length = 1),
|
||||||
),
|
],
|
||||||
[],
|
spaces: [
|
||||||
|
LineComment(
|
||||||
|
" comment after",
|
||||||
),
|
),
|
||||||
[
|
],
|
||||||
LineComment(
|
type_defs: [],
|
||||||
" comment after",
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@0-3 Identifier(
|
||||||
|
"foo",
|
||||||
),
|
),
|
||||||
],
|
@6-7 Num(
|
||||||
),
|
"1",
|
||||||
]
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
|
@ -1,46 +1,54 @@
|
||||||
[
|
Defs {
|
||||||
@0-24 SpaceAfter(
|
tags: [
|
||||||
SpaceBefore(
|
Index(2147483648),
|
||||||
Value(
|
],
|
||||||
Body(
|
regions: [
|
||||||
@0-4 Identifier(
|
@0-24,
|
||||||
"main",
|
],
|
||||||
),
|
space_before: [
|
||||||
@11-24 SpaceBefore(
|
Slice(start = 0, length = 0),
|
||||||
Defs(
|
],
|
||||||
[
|
space_after: [
|
||||||
@11-17 Value(
|
Slice(start = 0, length = 1),
|
||||||
Body(
|
],
|
||||||
@11-12 Identifier(
|
spaces: [
|
||||||
"i",
|
Newline,
|
||||||
),
|
],
|
||||||
@15-17 Num(
|
type_defs: [],
|
||||||
"64",
|
value_defs: [
|
||||||
),
|
Body(
|
||||||
),
|
@0-4 Identifier(
|
||||||
|
"main",
|
||||||
|
),
|
||||||
|
@11-24 SpaceBefore(
|
||||||
|
Defs(
|
||||||
|
[
|
||||||
|
@11-17 Value(
|
||||||
|
Body(
|
||||||
|
@11-12 Identifier(
|
||||||
|
"i",
|
||||||
|
),
|
||||||
|
@15-17 Num(
|
||||||
|
"64",
|
||||||
),
|
),
|
||||||
],
|
|
||||||
@23-24 SpaceBefore(
|
|
||||||
Var {
|
|
||||||
module_name: "",
|
|
||||||
ident: "i",
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
@23-24 SpaceBefore(
|
||||||
|
Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "i",
|
||||||
|
},
|
||||||
[
|
[
|
||||||
Newline,
|
Newline,
|
||||||
|
Newline,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
[],
|
|
||||||
),
|
),
|
||||||
[
|
],
|
||||||
Newline,
|
}
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,103 +1,111 @@
|
||||||
[
|
Defs {
|
||||||
@0-115 SpaceAfter(
|
tags: [
|
||||||
SpaceBefore(
|
Index(2147483648),
|
||||||
Value(
|
],
|
||||||
Body(
|
regions: [
|
||||||
@0-4 Identifier(
|
@0-115,
|
||||||
"main",
|
],
|
||||||
),
|
space_before: [
|
||||||
@11-115 SpaceBefore(
|
Slice(start = 0, length = 0),
|
||||||
Defs(
|
],
|
||||||
[
|
space_after: [
|
||||||
@43-93 Value(
|
Slice(start = 0, length = 1),
|
||||||
AnnotatedBody {
|
],
|
||||||
ann_pattern: @11-23 Identifier(
|
spaces: [
|
||||||
"wrappedNotEq",
|
Newline,
|
||||||
),
|
],
|
||||||
ann_type: @26-38 Function(
|
type_defs: [],
|
||||||
[
|
value_defs: [
|
||||||
@26-27 BoundVariable(
|
Body(
|
||||||
"a",
|
@0-4 Identifier(
|
||||||
),
|
"main",
|
||||||
@29-30 BoundVariable(
|
),
|
||||||
"a",
|
@11-115 SpaceBefore(
|
||||||
),
|
Defs(
|
||||||
],
|
[
|
||||||
@34-38 Apply(
|
@43-93 Value(
|
||||||
"",
|
AnnotatedBody {
|
||||||
"Bool",
|
ann_pattern: @11-23 Identifier(
|
||||||
[],
|
"wrappedNotEq",
|
||||||
),
|
|
||||||
),
|
|
||||||
comment: None,
|
|
||||||
body_pattern: @43-55 Identifier(
|
|
||||||
"wrappedNotEq",
|
|
||||||
),
|
|
||||||
body_expr: @58-93 Closure(
|
|
||||||
[
|
|
||||||
@59-63 Identifier(
|
|
||||||
"num1",
|
|
||||||
),
|
|
||||||
@65-69 Identifier(
|
|
||||||
"num2",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@81-93 SpaceBefore(
|
|
||||||
BinOps(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
@81-85 Var {
|
|
||||||
module_name: "",
|
|
||||||
ident: "num1",
|
|
||||||
},
|
|
||||||
@86-88 NotEquals,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@89-93 Var {
|
|
||||||
module_name: "",
|
|
||||||
ident: "num2",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
ann_type: @26-38 Function(
|
||||||
@99-115 SpaceBefore(
|
|
||||||
Apply(
|
|
||||||
@99-111 Var {
|
|
||||||
module_name: "",
|
|
||||||
ident: "wrappedNotEq",
|
|
||||||
},
|
|
||||||
[
|
[
|
||||||
@112-113 Num(
|
@26-27 BoundVariable(
|
||||||
"2",
|
"a",
|
||||||
),
|
),
|
||||||
@114-115 Num(
|
@29-30 BoundVariable(
|
||||||
"3",
|
"a",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Space,
|
@34-38 Apply(
|
||||||
|
"",
|
||||||
|
"Bool",
|
||||||
|
[],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
[
|
comment: None,
|
||||||
Newline,
|
body_pattern: @43-55 Identifier(
|
||||||
Newline,
|
"wrappedNotEq",
|
||||||
],
|
),
|
||||||
),
|
body_expr: @58-93 Closure(
|
||||||
|
[
|
||||||
|
@59-63 Identifier(
|
||||||
|
"num1",
|
||||||
|
),
|
||||||
|
@65-69 Identifier(
|
||||||
|
"num2",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@81-93 SpaceBefore(
|
||||||
|
BinOps(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
@81-85 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "num1",
|
||||||
|
},
|
||||||
|
@86-88 NotEquals,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@89-93 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "num2",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@99-115 SpaceBefore(
|
||||||
|
Apply(
|
||||||
|
@99-111 Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "wrappedNotEq",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
@112-113 Num(
|
||||||
|
"2",
|
||||||
|
),
|
||||||
|
@114-115 Num(
|
||||||
|
"3",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Space,
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
Newline,
|
Newline,
|
||||||
|
Newline,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
[],
|
|
||||||
),
|
),
|
||||||
[
|
],
|
||||||
Newline,
|
}
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
[
|
Defs {
|
||||||
@0-9 SpaceAfter(
|
tags: [
|
||||||
SpaceBefore(
|
Index(0),
|
||||||
Type(
|
],
|
||||||
Opaque {
|
regions: [
|
||||||
header: TypeHeader {
|
@0-9,
|
||||||
name: @0-3 "Age",
|
],
|
||||||
vars: [],
|
space_before: [
|
||||||
},
|
Slice(start = 0, length = 0),
|
||||||
typ: @7-9 Apply(
|
],
|
||||||
"",
|
space_after: [
|
||||||
"U8",
|
Slice(start = 0, length = 1),
|
||||||
[],
|
],
|
||||||
),
|
spaces: [
|
||||||
derived: None,
|
Newline,
|
||||||
},
|
],
|
||||||
|
type_defs: [
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader {
|
||||||
|
name: @0-3 "Age",
|
||||||
|
vars: [],
|
||||||
|
},
|
||||||
|
typ: @7-9 Apply(
|
||||||
|
"",
|
||||||
|
"U8",
|
||||||
|
[],
|
||||||
),
|
),
|
||||||
[],
|
derived: None,
|
||||||
),
|
},
|
||||||
[
|
],
|
||||||
Newline,
|
value_defs: [],
|
||||||
],
|
}
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,53 +1,61 @@
|
||||||
[
|
Defs {
|
||||||
@0-53 SpaceAfter(
|
tags: [
|
||||||
SpaceBefore(
|
Index(0),
|
||||||
Type(
|
],
|
||||||
Opaque {
|
regions: [
|
||||||
header: TypeHeader {
|
@0-53,
|
||||||
name: @0-10 "Bookmark",
|
],
|
||||||
vars: [
|
space_before: [
|
||||||
@9-10 Identifier(
|
Slice(start = 0, length = 0),
|
||||||
"a",
|
],
|
||||||
),
|
space_after: [
|
||||||
],
|
Slice(start = 0, length = 1),
|
||||||
},
|
],
|
||||||
typ: @14-53 Record {
|
spaces: [
|
||||||
fields: [
|
Newline,
|
||||||
@16-28 RequiredValue(
|
],
|
||||||
@16-23 "chapter",
|
type_defs: [
|
||||||
[],
|
Opaque {
|
||||||
@25-28 Apply(
|
header: TypeHeader {
|
||||||
"",
|
name: @0-10 "Bookmark",
|
||||||
"Str",
|
vars: [
|
||||||
[],
|
@9-10 Identifier(
|
||||||
),
|
"a",
|
||||||
),
|
),
|
||||||
@30-41 RequiredValue(
|
],
|
||||||
@30-36 "stanza",
|
},
|
||||||
[],
|
typ: @14-53 Record {
|
||||||
@38-41 Apply(
|
fields: [
|
||||||
"",
|
@16-28 RequiredValue(
|
||||||
"Str",
|
@16-23 "chapter",
|
||||||
[],
|
[],
|
||||||
),
|
@25-28 Apply(
|
||||||
),
|
"",
|
||||||
@43-51 RequiredValue(
|
"Str",
|
||||||
@43-48 "notes",
|
[],
|
||||||
[],
|
),
|
||||||
@50-51 BoundVariable(
|
),
|
||||||
"a",
|
@30-41 RequiredValue(
|
||||||
),
|
@30-36 "stanza",
|
||||||
),
|
[],
|
||||||
],
|
@38-41 Apply(
|
||||||
ext: None,
|
"",
|
||||||
},
|
"Str",
|
||||||
derived: None,
|
[],
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
[],
|
@43-51 RequiredValue(
|
||||||
),
|
@43-48 "notes",
|
||||||
[
|
[],
|
||||||
Newline,
|
@50-51 BoundVariable(
|
||||||
],
|
"a",
|
||||||
),
|
),
|
||||||
]
|
),
|
||||||
|
],
|
||||||
|
ext: None,
|
||||||
|
},
|
||||||
|
derived: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
value_defs: [],
|
||||||
|
}
|
||||||
|
|
|
@ -1,65 +1,68 @@
|
||||||
[
|
Defs {
|
||||||
@12-19 SpaceBefore(
|
tags: [
|
||||||
Value(
|
Index(2147483648),
|
||||||
Body(
|
Index(2147483649),
|
||||||
@12-15 Identifier(
|
Index(2147483650),
|
||||||
"foo",
|
],
|
||||||
),
|
regions: [
|
||||||
@18-19 Num(
|
@12-19,
|
||||||
"1",
|
@33-43,
|
||||||
|
@44-57,
|
||||||
|
],
|
||||||
|
space_before: [
|
||||||
|
Slice(start = 0, length = 1),
|
||||||
|
Slice(start = 1, length = 3),
|
||||||
|
Slice(start = 4, length = 1),
|
||||||
|
],
|
||||||
|
space_after: [
|
||||||
|
Slice(start = 1, length = 0),
|
||||||
|
Slice(start = 4, length = 0),
|
||||||
|
Slice(start = 5, length = 2),
|
||||||
|
],
|
||||||
|
spaces: [
|
||||||
|
LineComment(
|
||||||
|
" comment 1",
|
||||||
|
),
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
LineComment(
|
||||||
|
" comment 2",
|
||||||
|
),
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
LineComment(
|
||||||
|
" comment n",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
type_defs: [],
|
||||||
|
value_defs: [
|
||||||
|
Body(
|
||||||
|
@12-15 Identifier(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
|
@18-19 Num(
|
||||||
|
"1",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Body(
|
||||||
|
@33-36 Identifier(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
|
@39-43 Str(
|
||||||
|
PlainLine(
|
||||||
|
"hi",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
[
|
Body(
|
||||||
LineComment(
|
@44-47 Identifier(
|
||||||
" comment 1",
|
"baz",
|
||||||
),
|
),
|
||||||
],
|
@50-57 Str(
|
||||||
),
|
PlainLine(
|
||||||
@33-43 SpaceBefore(
|
"stuff",
|
||||||
Value(
|
|
||||||
Body(
|
|
||||||
@33-36 Identifier(
|
|
||||||
"bar",
|
|
||||||
),
|
|
||||||
@39-43 Str(
|
|
||||||
PlainLine(
|
|
||||||
"hi",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
[
|
],
|
||||||
Newline,
|
}
|
||||||
Newline,
|
|
||||||
LineComment(
|
|
||||||
" comment 2",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
@44-57 SpaceAfter(
|
|
||||||
SpaceBefore(
|
|
||||||
Value(
|
|
||||||
Body(
|
|
||||||
@44-47 Identifier(
|
|
||||||
"baz",
|
|
||||||
),
|
|
||||||
@50-57 Str(
|
|
||||||
PlainLine(
|
|
||||||
"stuff",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
LineComment(
|
|
||||||
" comment n",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
|
@ -3328,8 +3328,6 @@ fn content_to_err_type(
|
||||||
RangedNumber(typ, range) => {
|
RangedNumber(typ, range) => {
|
||||||
let err_type = var_to_err_type(subs, state, typ);
|
let err_type = var_to_err_type(subs, state, typ);
|
||||||
|
|
||||||
dbg!(range);
|
|
||||||
|
|
||||||
if state.context == ErrorTypeContext::ExpandRanges {
|
if state.context == ErrorTypeContext::ExpandRanges {
|
||||||
let mut types = Vec::new();
|
let mut types = Vec::new();
|
||||||
for var in range.variable_slice() {
|
for var in range.variable_slice() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue