mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Merge branch 'trunk' into parser-with-progress
This commit is contained in:
commit
7feada88e4
16 changed files with 191 additions and 37 deletions
|
@ -701,7 +701,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
add_type(
|
||||
Symbol::LIST_REPEAT,
|
||||
top_level_function(
|
||||
vec![nat_type(), flex(TVAR2)],
|
||||
vec![nat_type(), flex(TVAR1)],
|
||||
Box::new(list_type(flex(TVAR1))),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::procedure::References;
|
||||
use inlinable_string::InlinableString;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::{Located, Region};
|
||||
|
@ -113,7 +114,7 @@ impl<'a> Env<'a> {
|
|||
Ok(symbol)
|
||||
}
|
||||
None => Err(RuntimeError::ValueNotExposed {
|
||||
module_name,
|
||||
module_name: ModuleName::from(module_name),
|
||||
ident,
|
||||
region,
|
||||
}),
|
||||
|
|
|
@ -2782,7 +2782,25 @@ pub fn with_hole<'a>(
|
|||
use crate::layout::UnionVariant::*;
|
||||
let arena = env.arena;
|
||||
|
||||
let variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
||||
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
||||
|
||||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"UnresolvedTypeVar {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Erroneous {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
match variant {
|
||||
Never => unreachable!(
|
||||
|
@ -4581,9 +4599,23 @@ fn from_can_when<'a>(
|
|||
}
|
||||
let opt_branches = to_opt_branches(env, region, branches, layout_cache);
|
||||
|
||||
let cond_layout = layout_cache
|
||||
.from_var(env.arena, cond_var, env.subs)
|
||||
.unwrap_or_else(|err| panic!("TODO turn this into a RuntimeError {:?}", err));
|
||||
let cond_layout = match layout_cache.from_var(env.arena, cond_var, env.subs) {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"UnresolvedTypeVar {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Erroneous {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
let ret_layout = layout_cache
|
||||
.from_var(env.arena, expr_var, env.subs)
|
||||
|
@ -6039,7 +6071,15 @@ fn from_can_pattern_help<'a>(
|
|||
use crate::exhaustive::Union;
|
||||
use crate::layout::UnionVariant::*;
|
||||
|
||||
let variant = crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs);
|
||||
let res_variant = crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs);
|
||||
|
||||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Err(RuntimeError::UnresolvedTypeVar)
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => return Err(RuntimeError::ErroneousType),
|
||||
};
|
||||
|
||||
let result = match variant {
|
||||
Never => unreachable!(
|
||||
|
|
|
@ -1324,7 +1324,11 @@ impl<'a> WrappedVariant<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn union_sorted_tags<'a>(arena: &'a Bump, var: Variable, subs: &Subs) -> UnionVariant<'a> {
|
||||
pub fn union_sorted_tags<'a>(
|
||||
arena: &'a Bump,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
||||
let var =
|
||||
if let Content::RecursionVar { structure, .. } = subs.get_without_compacting(var).content {
|
||||
structure
|
||||
|
@ -1338,10 +1342,11 @@ pub fn union_sorted_tags<'a>(arena: &'a Bump, var: Variable, subs: &Subs) -> Uni
|
|||
let opt_rec_var = get_recursion_var(subs, var);
|
||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs)
|
||||
}
|
||||
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
||||
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
||||
};
|
||||
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_recursion_var(subs: &Subs, var: Variable) -> Option<Variable> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use inlinable_string::InlinableString;
|
||||
use roc_collections::all::MutSet;
|
||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||
use roc_module::ident::{Ident, Lowercase, ModuleName, TagName};
|
||||
use roc_module::operator::BinOp;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_parse::ast::Base;
|
||||
|
@ -117,9 +117,13 @@ pub enum RuntimeError {
|
|||
UnsupportedPattern(Region),
|
||||
// Example: when 1 is 1.X -> 32
|
||||
MalformedPattern(MalformedPatternProblem, Region),
|
||||
|
||||
UnresolvedTypeVar,
|
||||
ErroneousType,
|
||||
|
||||
LookupNotInScope(Located<InlinableString>, MutSet<Box<str>>),
|
||||
ValueNotExposed {
|
||||
module_name: InlinableString,
|
||||
module_name: ModuleName,
|
||||
ident: InlinableString,
|
||||
region: Region,
|
||||
},
|
||||
|
|
|
@ -344,6 +344,11 @@ fn pretty_runtime_error<'b>(
|
|||
unreachable!("")
|
||||
}
|
||||
|
||||
RuntimeError::UnresolvedTypeVar | RuntimeError::ErroneousType => {
|
||||
// only generated during layout generation
|
||||
unreachable!("")
|
||||
}
|
||||
|
||||
RuntimeError::Shadowing {
|
||||
original_region,
|
||||
shadow,
|
||||
|
@ -443,7 +448,20 @@ fn pretty_runtime_error<'b>(
|
|||
RuntimeError::UnsupportedPattern(_) => {
|
||||
todo!("unsupported patterns are currently not parsed!")
|
||||
}
|
||||
RuntimeError::ValueNotExposed { .. } => todo!("value not exposed"),
|
||||
RuntimeError::ValueNotExposed { module_name, ident, region } => {
|
||||
alloc.stack(vec![
|
||||
alloc.concat(vec![
|
||||
alloc.reflow("The "),
|
||||
alloc.module_name(module_name),
|
||||
alloc.reflow(" module does not expose a "),
|
||||
alloc.string(ident.to_string()),
|
||||
alloc.reflow(" value:"),
|
||||
]),
|
||||
alloc.region(region),
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
RuntimeError::ModuleNotImported {
|
||||
module_name,
|
||||
imported_modules,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use inlinable_string::InlinableString;
|
||||
use roc_module::ident::Ident;
|
||||
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
||||
use roc_module::ident::{Lowercase, ModuleName, TagName, Uppercase};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
@ -316,6 +316,17 @@ impl<'a> RocDocAllocator<'a> {
|
|||
self.text(name).annotate(Annotation::Module)
|
||||
}
|
||||
|
||||
pub fn module_name(&'a self, name: ModuleName) -> DocBuilder<'a, Self, Annotation> {
|
||||
let name = if name.is_empty() {
|
||||
// Render the app module as "app"
|
||||
"app".to_string()
|
||||
} else {
|
||||
name.as_str().to_string()
|
||||
};
|
||||
|
||||
self.text(name).annotate(Annotation::Module)
|
||||
}
|
||||
|
||||
pub fn inlinable_string(&'a self, s: InlinableString) -> DocBuilder<'a, Self, Annotation> {
|
||||
self.text(format!("{}", s)).annotate(Annotation::Module)
|
||||
}
|
||||
|
|
|
@ -229,6 +229,27 @@ mod test_reporting {
|
|||
.replace(UNDERLINE_CODE, "<underline>")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_not_exposed() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
List.foobar 1 2
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||
|
||||
The List module does not expose a foobar value:
|
||||
|
||||
1│ List.foobar 1 2
|
||||
^^^^^^^^^^^
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_unused_def() {
|
||||
report_problem_as(
|
||||
|
|
|
@ -61,6 +61,8 @@ These are potentially inspirational resources for the editor's design.
|
|||
- All `when ... is` should be updated if the type is changed, e.g. adding Indigo to the Color type should add an arm everywhere where `when color is` is used.
|
||||
* When a function is called like `foo(false)`, the name of the boolean argument should be shown automatically; `foo(`*is_active:*`false)`. This should be done for booleans and numbers.
|
||||
* Suggest automatically creating a function if the compiler says it does not exist.
|
||||
* Integrated search:
|
||||
* Searchbar for examples/docs. With permission search strings could be shared with the platform/package authors so they know exactly what their users are struggling with.
|
||||
|
||||
|
||||
### Non-Code Related Inspiration
|
||||
|
@ -81,6 +83,7 @@ These are potentially inspirational resources for the editor's design.
|
|||
* GPT-3 can generate correct python functions based on a comment describing the functionality, video [here](https://www.youtube.com/watch?v=utuz7wBGjKM). It's possible that training a model using ast's may lead to better results than text based models.
|
||||
* Users with large private code bases could (re)train a publicly available error recovery model to experience benefits without having to share their code.
|
||||
* It could be useful to a user who is creating a function to show them the most similar function (type signature, name, comment) in a public+their private database. Say I was using a web framework and I just created a function that has a multipart form as argument, it would be great to have an example instantly available.
|
||||
* A simpler start for this idea without user data gathering: how the user a code snippet that is most similar to what they are currently writing. Snippets can be aggregated from examples, tests, docstrings at zero cost to the package/platform authors.
|
||||
* Voice input:
|
||||
* Good for accessibility.
|
||||
* https://www.youtube.com/watch?v=Ffa3cXM7bjc is interesting for inspiration.
|
||||
|
@ -104,12 +107,39 @@ These are potentially inspirational resources for the editor's design.
|
|||
* Do a normal run, and save the input and output of the selected function.
|
||||
* Generate a unit test with that input-output pair
|
||||
|
||||
## Documentation
|
||||
|
||||
* Ability to see module as it would be presented on a package website.
|
||||
* Modern editors may guide developers to the source code too easily.
|
||||
The API and documentation are meant to interface with humans.
|
||||
|
||||
## General Thoughts/Ideas
|
||||
|
||||
Thoughts and ideas possibly taken from above inspirations or separate.
|
||||
|
||||
* ACCESSIBILITY!!!
|
||||
* ACCESSIBILITY === EMPATHY
|
||||
* Visual Imapirments
|
||||
No Animation is most benign form of cognitive disabity but really important base line of people with tense nerve system.
|
||||
Insensitivity to certain or all colors.
|
||||
Need of highcontrast
|
||||
Or Everything Magnified for me with no glasses.
|
||||
Or Total blindness where we need to trough sound to communicate to the user
|
||||
Screen readers read trees of labeled elements. Each platform has different apis, but I think they are horrible. Just close your eyes and imagine listening to screen reader all day while you are using this majectic machines called computers.
|
||||
But blind people walk with a tool and they can react much better to sound/space relations than full on visal majority does. They are acute to sound as a spatial hint. And a hand for most of them is a very sensitive tool that can make sounds in space.
|
||||
Imagine if everytime for the user doesnt want to rely on shining rendered pixels on the screen for a feedback from machine, we make a accoustic room simulation, where with moving the "stick", either with mouse or with key arrows, we bump into one of the objects and that produces certain contextually appropriate sound (clean)*ding*
|
||||
|
||||
On the each level of abstraction they can make sounds more deeper, so then when you type letters you feel like you are playing with the sand (soft)*shh*. We would need help from some sound engeneer about it, but imagine moving down, which can be voice trigered command for motion impaired, you hear (soft)*pup* and the name of the module, and then you have options and commands appropriate for the module, they could map to those basic 4 buttons that we trained user on, and he would shortcut all the soft talk with click of a button. Think of the satisfaction when you can skip the dialog of the game and get straight into action. (X) Open functions! each function would make a sound and say its name, unless you press search and start searching for a specific function inside module, if you want one you select or move to next.
|
||||
|
||||
* Motor impariments
|
||||
[rant]BACKS OF CODERS ARE NOT HEALTHY! We need to change that![/neverstop]
|
||||
Too much mouse waving and sitting for too long is bad for humans.
|
||||
Keyboard is basic accessability tool but
|
||||
Keyboard is also optional, some people have too shaky hands even for keyboard.
|
||||
They rely on eye tracking to move mouse cursor arond.
|
||||
If we employ _some_ voice recognition functions we could make same interface as we could do for consoles where 4+2 buttons and directional pad would suffice.
|
||||
That is 10 phrases that need to be pulled trough as many possible translations so people don't have to pretend that they are from Maine or Texas so they get voice recognition to work. Believe me I was there with Apple's Siri :D That is why we have 10 phrases for movement and management and most basic syntax.
|
||||
|
||||
|
||||
* Nice backtraces that highlight important information
|
||||
* Ability to show import connection within project visually
|
||||
* This could be done by drawing connections between files or functions in the tree view. This would make it easier for people to get their bearings in new big projects.
|
||||
|
|
|
@ -12,6 +12,7 @@ use inlinable_string::InlinableString;
|
|||
use roc_can::expr::Recursive;
|
||||
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::operator::CalledVia;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||
|
@ -178,7 +179,7 @@ impl<'a> Env<'a> {
|
|||
Ok(symbol)
|
||||
}
|
||||
None => Err(RuntimeError::ValueNotExposed {
|
||||
module_name,
|
||||
module_name: ModuleName::from(module_name),
|
||||
ident,
|
||||
region,
|
||||
}),
|
||||
|
|
|
@ -304,7 +304,13 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
render::render_expr2(&size, &expr2, CODE_TXT_XY.into(), &mut glyph_brush);
|
||||
render::render_expr2(
|
||||
&arena,
|
||||
&size,
|
||||
&expr2,
|
||||
CODE_TXT_XY.into(),
|
||||
&mut glyph_brush,
|
||||
);
|
||||
}
|
||||
|
||||
match draw_all_rects(
|
||||
|
|
|
@ -351,12 +351,13 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
|
||||
ed_model.selection_opt = None;
|
||||
}
|
||||
'\u{3}'
|
||||
| '\u{16}'
|
||||
| '\u{30}'
|
||||
| '\u{e000}'..='\u{f8ff}'
|
||||
| '\u{f0000}'..='\u{ffffd}'
|
||||
| '\u{100000}'..='\u{10fffd}' => {
|
||||
'\u{3}' // Ctrl + C
|
||||
| '\u{16}' // Ctrl + V
|
||||
| '\u{30}' // Ctrl + X
|
||||
| '\u{e000}'..='\u{f8ff}' // http://www.unicode.org/faq/private_use.html
|
||||
| '\u{f0000}'..='\u{ffffd}' // ^
|
||||
| '\u{100000}'..='\u{10fffd}' // ^
|
||||
=> {
|
||||
// chars that can be ignored
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use bumpalo::Bump;
|
||||
use cgmath::Vector2;
|
||||
use wgpu_glyph::GlyphBrush;
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
@ -8,53 +9,68 @@ use crate::{
|
|||
primitives::text::{queue_code_text_draw, Text},
|
||||
style::CODE_FONT_SIZE,
|
||||
},
|
||||
lang::ast::Expr2,
|
||||
lang::ast::{Expr2, FloatVal, IntVal},
|
||||
};
|
||||
|
||||
pub fn render_expr2(
|
||||
pub fn render_expr2<'a>(
|
||||
_arena: &'a Bump,
|
||||
size: &PhysicalSize<u32>,
|
||||
expr2: &Expr2,
|
||||
position: Vector2<f32>,
|
||||
glyph_brush: &mut GlyphBrush<()>,
|
||||
) {
|
||||
use Expr2::*;
|
||||
|
||||
let area_bounds = (size.width as f32, size.height as f32).into();
|
||||
|
||||
match expr2 {
|
||||
SmallInt {
|
||||
Expr2::SmallInt {
|
||||
number,
|
||||
..
|
||||
// text,
|
||||
// style, pretending always decimal for now
|
||||
// var,
|
||||
} => {
|
||||
let text = match number {
|
||||
IntVal::I64(val) => format!("{}", val),
|
||||
IntVal::I32(val) => format!("{}", val),
|
||||
IntVal::I16(val) => format!("{}", val),
|
||||
IntVal::I8(val) => format!("{}", val),
|
||||
IntVal::U64(val) => format!("{}", val),
|
||||
IntVal::U32(val ) => format!("{}", val),
|
||||
IntVal::U16(val) => format!("{}", val),
|
||||
IntVal::U8(val) => format!("{}", val),
|
||||
};
|
||||
|
||||
let code_text = Text {
|
||||
position,
|
||||
area_bounds,
|
||||
color: CODE_COLOR.into(),
|
||||
text: format!("{:?}", number),
|
||||
text,
|
||||
size: CODE_FONT_SIZE,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
queue_code_text_draw(&code_text, glyph_brush);
|
||||
}
|
||||
Float {
|
||||
Expr2::Float {
|
||||
number,
|
||||
..
|
||||
} => {
|
||||
let text = match number {
|
||||
FloatVal::F64(val) => format!("{}", val),
|
||||
FloatVal::F32(val) => format!("{}", val),
|
||||
};
|
||||
|
||||
let code_text = Text {
|
||||
position,
|
||||
area_bounds,
|
||||
color: CODE_COLOR.into(),
|
||||
text: format!("{:?}", number),
|
||||
text,
|
||||
size: CODE_FONT_SIZE,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
queue_code_text_draw(&code_text, glyph_brush);
|
||||
}
|
||||
rest => panic!("implement {:?} render", rest)
|
||||
rest => todo!("implement {:?} render", rest)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
interface File
|
||||
exposes [ FileReadErr, FileOpenErr, FileWriteErr, DirReadErr, readUtf8 ]
|
||||
imports [ Task.{ Task }, Effect.{ after }, Path ]
|
||||
imports [ Task.{ Task }, fx.Effect.{ after }, Path ]
|
||||
|
||||
Path : Path.Path
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ platform folkertdev/foo
|
|||
packages {}
|
||||
imports [ Task, File ]
|
||||
provides [ mainForHost ]
|
||||
effects Effect
|
||||
effects fx.Effect
|
||||
{
|
||||
# TODO change sig to Effect { errno : I32, bytes : List U8 }
|
||||
readAllUtf8 : Str -> Effect { errno : I64, bytes : Str },
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
interface Task
|
||||
exposes [ Task, succeed, fail, after, map, putLine ]
|
||||
imports [ Effect ]
|
||||
imports [ fx.Effect ]
|
||||
|
||||
|
||||
Task ok err : Effect.Effect (Result ok err)
|
||||
|
@ -28,7 +28,7 @@ map = \effect, transform ->
|
|||
Effect.after effect \result ->
|
||||
when result is
|
||||
Ok a -> Task.succeed (transform a)
|
||||
Err err -> Effect.always (Err err) # Task.fail err does not work. WEIRD!
|
||||
Err err -> Task.fail err
|
||||
|
||||
putLine : Str -> Task {} *
|
||||
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue