mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
wip
This commit is contained in:
parent
a0d39ff10f
commit
e595c14fae
@ -178,12 +178,13 @@ pub fn canonicalize_expr<'a>(
|
||||
|
||||
let (expr, output) = match expr {
|
||||
ast::Expr::Num(string) => {
|
||||
let answer = num_expr_from_result(var_store, finish_parsing_int(*string), env);
|
||||
let answer = num_expr_from_result(var_store, finish_parsing_int(*string), region, env);
|
||||
|
||||
(answer, Output::default())
|
||||
}
|
||||
ast::Expr::Float(string) => {
|
||||
let answer = float_expr_from_result(var_store, finish_parsing_float(string), env);
|
||||
let answer =
|
||||
float_expr_from_result(var_store, finish_parsing_float(string), region, env);
|
||||
|
||||
(answer, Output::default())
|
||||
}
|
||||
@ -630,7 +631,7 @@ pub fn canonicalize_expr<'a>(
|
||||
result = result.map(i64::neg);
|
||||
}
|
||||
|
||||
let answer = int_expr_from_result(var_store, result, env);
|
||||
let answer = int_expr_from_result(var_store, result, region, env);
|
||||
|
||||
(answer, Output::default())
|
||||
}
|
||||
|
@ -3,22 +3,30 @@ use crate::expr::Expr;
|
||||
use roc_parse::ast::Base;
|
||||
use roc_problem::can::Problem;
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
use roc_region::all::Region;
|
||||
use roc_types::subs::VarStore;
|
||||
use std::i64;
|
||||
use std::num::{ParseFloatError, ParseIntError};
|
||||
|
||||
// TODO distinguish number parsing failures
|
||||
//
|
||||
// We're waiting for rust here, see https://github.com/rust-lang/rust/issues/22639
|
||||
// There is a nightly API for exposing the parse error.
|
||||
|
||||
#[inline(always)]
|
||||
pub fn num_expr_from_result(
|
||||
var_store: &mut VarStore,
|
||||
result: Result<i64, &str>,
|
||||
result: Result<i64, (&str, ParseIntError)>,
|
||||
region: Region,
|
||||
env: &mut Env,
|
||||
) -> Expr {
|
||||
match result {
|
||||
Ok(int) => Expr::Num(var_store.fresh(), int),
|
||||
Err(raw) => {
|
||||
Err((raw, _error)) => {
|
||||
// (Num *) compiles to Int if it doesn't
|
||||
// get specialized to something else first,
|
||||
// so use int's overflow bounds here.
|
||||
let runtime_error = IntOutsideRange(raw.into());
|
||||
let runtime_error = IntOutsideRange(raw.into(), region);
|
||||
|
||||
env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||
|
||||
@ -30,14 +38,15 @@ pub fn num_expr_from_result(
|
||||
#[inline(always)]
|
||||
pub fn int_expr_from_result(
|
||||
var_store: &mut VarStore,
|
||||
result: Result<i64, &str>,
|
||||
result: Result<i64, (&str, ParseIntError)>,
|
||||
region: Region,
|
||||
env: &mut Env,
|
||||
) -> Expr {
|
||||
// Int stores a variable to generate better error messages
|
||||
match result {
|
||||
Ok(int) => Expr::Int(var_store.fresh(), int),
|
||||
Err(raw) => {
|
||||
let runtime_error = IntOutsideRange(raw.into());
|
||||
Err((raw, _error)) => {
|
||||
let runtime_error = IntOutsideRange(raw.into(), region);
|
||||
|
||||
env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||
|
||||
@ -49,14 +58,15 @@ pub fn int_expr_from_result(
|
||||
#[inline(always)]
|
||||
pub fn float_expr_from_result(
|
||||
var_store: &mut VarStore,
|
||||
result: Result<f64, &str>,
|
||||
result: Result<f64, (&str, ParseFloatError)>,
|
||||
region: Region,
|
||||
env: &mut Env,
|
||||
) -> Expr {
|
||||
// Float stores a variable to generate better error messages
|
||||
match result {
|
||||
Ok(float) => Expr::Float(var_store.fresh(), float),
|
||||
Err(raw) => {
|
||||
let runtime_error = FloatOutsideRange(raw.into());
|
||||
Err((raw, _error)) => {
|
||||
let runtime_error = FloatOutsideRange(raw.into(), region);
|
||||
|
||||
env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||
|
||||
@ -66,13 +76,13 @@ pub fn float_expr_from_result(
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn finish_parsing_int(raw: &str) -> Result<i64, &str> {
|
||||
pub fn finish_parsing_int(raw: &str) -> Result<i64, (&str, ParseIntError)> {
|
||||
// Ignore underscores.
|
||||
raw.replace("_", "").parse::<i64>().map_err(|_| raw)
|
||||
raw.replace("_", "").parse::<i64>().map_err(|e| (raw, e))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn finish_parsing_base(raw: &str, base: Base) -> Result<i64, &str> {
|
||||
pub fn finish_parsing_base(raw: &str, base: Base) -> Result<i64, (&str, ParseIntError)> {
|
||||
let radix = match base {
|
||||
Base::Hex => 16,
|
||||
Base::Octal => 8,
|
||||
@ -80,14 +90,15 @@ pub fn finish_parsing_base(raw: &str, base: Base) -> Result<i64, &str> {
|
||||
};
|
||||
|
||||
// Ignore underscores.
|
||||
i64::from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|_| raw)
|
||||
i64::from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn finish_parsing_float(raw: &str) -> Result<f64, &str> {
|
||||
pub fn finish_parsing_float(raw: &str) -> Result<f64, (&str, ParseFloatError)> {
|
||||
// Ignore underscores.
|
||||
match raw.replace("_", "").parse::<f64>() {
|
||||
Ok(float) if float.is_finite() => Ok(float),
|
||||
_ => Err(raw),
|
||||
Ok(_float) => panic!("TODO handle infinite float literal"),
|
||||
Err(e) => Err((raw, e)),
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ pub fn canonicalize_pattern<'a>(
|
||||
use roc_parse::ast::Pattern::*;
|
||||
use PatternType::*;
|
||||
|
||||
let can_pattern = match pattern {
|
||||
let can_pattern = match dbg!(pattern) {
|
||||
Identifier(name) => match scope.introduce(
|
||||
(*name).into(),
|
||||
&env.exposed_ident_ids,
|
||||
|
@ -72,7 +72,6 @@ pub enum RuntimeError {
|
||||
UnsupportedPattern(Region),
|
||||
// Example: when 1 is 1.X -> 32
|
||||
MalformedPattern(MalformedPatternProblem, Region),
|
||||
UnrecognizedFunctionName(Located<InlinableString>),
|
||||
LookupNotInScope(Located<InlinableString>, MutSet<Box<str>>),
|
||||
ValueNotExposed {
|
||||
module_name: InlinableString,
|
||||
@ -87,8 +86,8 @@ pub enum RuntimeError {
|
||||
InvalidPrecedence(PrecedenceProblem, Region),
|
||||
MalformedIdentifier(Box<str>, Region),
|
||||
MalformedClosure(Region),
|
||||
FloatOutsideRange(Box<str>),
|
||||
IntOutsideRange(Box<str>),
|
||||
FloatOutsideRange(Box<str>, Region),
|
||||
IntOutsideRange(Box<str>, Region),
|
||||
InvalidHex(std::num::ParseIntError, Box<str>),
|
||||
InvalidOctal(std::num::ParseIntError, Box<str>),
|
||||
InvalidBinary(std::num::ParseIntError, Box<str>),
|
||||
|
@ -372,39 +372,46 @@ fn pretty_runtime_error<'b>(
|
||||
hint,
|
||||
])
|
||||
}
|
||||
|
||||
other => {
|
||||
// // Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
||||
// UnsupportedPattern(Region),
|
||||
// UnrecognizedFunctionName(Located<InlinableString>),
|
||||
// SymbolNotExposed {
|
||||
// module_name: InlinableString,
|
||||
// ident: InlinableString,
|
||||
// region: Region,
|
||||
// },
|
||||
// ModuleNotImported {
|
||||
// module_name: InlinableString,
|
||||
// ident: InlinableString,
|
||||
// region: Region,
|
||||
// },
|
||||
// InvalidPrecedence(PrecedenceProblem, Region),
|
||||
// MalformedIdentifier(Box<str>, Region),
|
||||
// MalformedClosure(Region),
|
||||
// FloatOutsideRange(Box<str>),
|
||||
// IntOutsideRange(Box<str>),
|
||||
// InvalidHex(std::num::ParseIntError, Box<str>),
|
||||
// InvalidOctal(std::num::ParseIntError, Box<str>),
|
||||
// InvalidBinary(std::num::ParseIntError, Box<str>),
|
||||
// QualifiedPatternIdent(InlinableString),
|
||||
// CircularDef(
|
||||
// Vec<Located<Ident>>,
|
||||
// Vec<(Region /* pattern */, Region /* expr */)>,
|
||||
// ),
|
||||
//
|
||||
// /// When the author specifies a type annotation but no implementation
|
||||
// NoImplementation,
|
||||
todo!("TODO implement run time error reporting for {:?}", other)
|
||||
RuntimeError::UnsupportedPattern(_) => {
|
||||
todo!("unsupported patterns are currently not parsed!")
|
||||
}
|
||||
RuntimeError::ValueNotExposed { .. } => todo!("value not exposed"),
|
||||
RuntimeError::ModuleNotImported { .. } => todo!("module not imported"),
|
||||
RuntimeError::InvalidPrecedence(_, _) => {
|
||||
// do nothing, reported with PrecedenceProblem
|
||||
unreachable!()
|
||||
}
|
||||
RuntimeError::MalformedIdentifier(_, _) => {
|
||||
todo!("malformed identifier, currently gives a parse error and thus is unreachable")
|
||||
}
|
||||
RuntimeError::MalformedClosure(_) => todo!(""),
|
||||
RuntimeError::FloatOutsideRange(_raw_str, _region) => todo!(""),
|
||||
RuntimeError::IntOutsideRange(raw_str, region) => {
|
||||
let big_or_small = if raw_str.starts_with('-') {
|
||||
"small"
|
||||
} else {
|
||||
"big"
|
||||
};
|
||||
|
||||
let hint = alloc
|
||||
.hint()
|
||||
.append(alloc.reflow("Learn more about number literals at TODO"));
|
||||
|
||||
alloc.stack(vec![
|
||||
alloc.concat(vec![
|
||||
alloc.reflow("This integer literal is too "),
|
||||
alloc.text(big_or_small),
|
||||
alloc.reflow(":"),
|
||||
]),
|
||||
alloc.region(region),
|
||||
alloc.reflow("Roc uses signed 64-bit integers, allowing values between −9_223_372_036_854_775_808 and 9_223_372_036_854_775_807."),
|
||||
hint,
|
||||
])
|
||||
}
|
||||
RuntimeError::InvalidHex(_, _) => todo!("invalid hex, unreachable"),
|
||||
RuntimeError::InvalidOctal(_, _) => todo!("invalid octal, unreachable"),
|
||||
RuntimeError::InvalidBinary(_, _) => todo!("invalid binary, unreachable"),
|
||||
RuntimeError::NoImplementation => todo!("no implementation, unreachable"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3108,4 +3108,145 @@ mod test_reporting {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_out_of_range() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
x = 9_223_372_036_854_775_807_000
|
||||
|
||||
y = -9_223_372_036_854_775_807_000
|
||||
|
||||
x + y
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too small:
|
||||
|
||||
3 ┆ y = -9_223_372_036_854_775_807_000
|
||||
┆ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
1 ┆ x = 9_223_372_036_854_775_807_000
|
||||
┆ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_malformed() {
|
||||
// the generated messages here are incorrect. Waiting for a rust nightly feature to land,
|
||||
// see https://github.com/rust-lang/rust/issues/22639
|
||||
// this test is here to spot regressions in error reporting
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
dec = 100A
|
||||
|
||||
hex = 0xZZZ
|
||||
|
||||
oct = 0o9
|
||||
|
||||
bin = 0b2
|
||||
|
||||
dec + hex + oct + bin
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
3 ┆ hex = 0xZZZ
|
||||
┆ ^^^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
5 ┆ oct = 0o9
|
||||
┆ ^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
7 ┆ bin = 0b2
|
||||
┆ ^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
1 ┆ dec = 100A
|
||||
┆ ^^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn precedence_conflict() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
foo@bar
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This integer literal is too big:
|
||||
|
||||
1 ┆ dec = 100A
|
||||
┆ ^^^^
|
||||
|
||||
Roc uses signed 64-bit integers, allowing values between
|
||||
−9_223_372_036_854_775_808 and 9_223_372_036_854_775_807.
|
||||
|
||||
Hint: Learn more about number literals at TODO
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user