mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
pull in trunk, moved all pipelines to single file, renamed model to ed_model
This commit is contained in:
commit
659a77da9f
19 changed files with 2386 additions and 111 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2672,6 +2672,8 @@ dependencies = [
|
|||
"log",
|
||||
"maplit",
|
||||
"page_size",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
|
|
|
@ -484,6 +484,34 @@ fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn int_with_precision<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: i128,
|
||||
precision: &Builtin,
|
||||
) -> IntValue<'ctx> {
|
||||
match precision {
|
||||
Builtin::Usize => ptr_int(env.context, env.ptr_bytes).const_int(value as u64, false),
|
||||
Builtin::Int128 => const_i128(env, value),
|
||||
Builtin::Int64 => env.context.i64_type().const_int(value as u64, false),
|
||||
Builtin::Int32 => env.context.i32_type().const_int(value as u64, false),
|
||||
Builtin::Int16 => env.context.i16_type().const_int(value as u64, false),
|
||||
Builtin::Int8 => env.context.i8_type().const_int(value as u64, false),
|
||||
_ => panic!("Invalid layout for int literal = {:?}", precision),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float_with_precision<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: f64,
|
||||
precision: &Builtin,
|
||||
) -> FloatValue<'ctx> {
|
||||
match precision {
|
||||
Builtin::Float64 => env.context.f64_type().const_float(value),
|
||||
Builtin::Float32 => env.context.f32_type().const_float(value),
|
||||
_ => panic!("Invalid layout for float literal = {:?}", precision),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_exp_literal<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'_>,
|
||||
|
@ -492,22 +520,16 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
|
|||
use roc_mono::ir::Literal::*;
|
||||
|
||||
match literal {
|
||||
Int(int) =>
|
||||
(match layout {
|
||||
Layout::Builtin(Builtin::Usize) => ptr_int(env.context, env.ptr_bytes),
|
||||
Layout::Builtin(Builtin::Int128) => env.context.i128_type(), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */
|
||||
Layout::Builtin(Builtin::Int64) => env.context.i64_type(),
|
||||
Layout::Builtin(Builtin::Int32) => env.context.i32_type(),
|
||||
Layout::Builtin(Builtin::Int16) => env.context.i16_type(),
|
||||
Layout::Builtin(Builtin::Int8) => env.context.i8_type(),
|
||||
Int(int) => match layout {
|
||||
Layout::Builtin(builtin) => int_with_precision(env, *int as i128, builtin).into(),
|
||||
_ => panic!("Invalid layout for int literal = {:?}", layout),
|
||||
}).const_int(*int as u64, false).into(),
|
||||
Float(num) =>
|
||||
(match layout {
|
||||
Layout::Builtin(Builtin::Float64) => env.context.f64_type(),
|
||||
Layout::Builtin(Builtin::Float32) => env.context.f32_type(),
|
||||
},
|
||||
|
||||
Float(float) => match layout {
|
||||
Layout::Builtin(builtin) => float_with_precision(env, *float, builtin).into(),
|
||||
_ => panic!("Invalid layout for float literal = {:?}", layout),
|
||||
}).const_float(*num).into(),
|
||||
},
|
||||
|
||||
Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(),
|
||||
Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(),
|
||||
Str(str_literal) => {
|
||||
|
@ -1494,9 +1516,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
call,
|
||||
layout,
|
||||
pass,
|
||||
fail: roc_mono::ir::Stmt::Unreachable,
|
||||
fail: roc_mono::ir::Stmt::Rethrow,
|
||||
} => {
|
||||
// when the fail case is just Unreachable, there is no cleanup work to do
|
||||
// when the fail case is just Rethrow, there is no cleanup work to do
|
||||
// so we can just treat this invoke as a normal call
|
||||
let stmt =
|
||||
roc_mono::ir::Stmt::Let(*symbol, Expr::Call(call.clone()), layout.clone(), pass);
|
||||
|
@ -1561,7 +1583,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
}
|
||||
},
|
||||
|
||||
Unreachable => {
|
||||
Rethrow => {
|
||||
cxa_rethrow_exception(env);
|
||||
|
||||
// used in exception handling
|
||||
|
@ -1783,6 +1805,22 @@ struct SwitchArgsIr<'a, 'ctx> {
|
|||
pub ret_type: BasicTypeEnum<'ctx>,
|
||||
}
|
||||
|
||||
fn const_i128<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, value: i128) -> IntValue<'ctx> {
|
||||
// TODO verify the order [a, b] is correct for larger numbers when we can parse them
|
||||
debug_assert!(value <= i64::MAX as i128);
|
||||
|
||||
// truncate the lower 64 bits
|
||||
let value = value as u128;
|
||||
let a = value as u64;
|
||||
|
||||
// get the upper 64 bits
|
||||
let b = (value >> 64) as u64;
|
||||
|
||||
env.context
|
||||
.i128_type()
|
||||
.const_int_arbitrary_precision(&[a, b])
|
||||
}
|
||||
|
||||
fn build_switch_ir<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
|
@ -1860,7 +1898,7 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
|||
ptr_int(env.context, env.ptr_bytes).const_int(*int as u64, false)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int64) => context.i64_type().const_int(*int as u64, false),
|
||||
Layout::Builtin(Builtin::Int128) => context.i128_type().const_int(*int as u64, false), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */
|
||||
Layout::Builtin(Builtin::Int128) => const_i128(env, *int as i128),
|
||||
Layout::Builtin(Builtin::Int32) => context.i32_type().const_int(*int as u64, false),
|
||||
Layout::Builtin(Builtin::Int16) => context.i16_type().const_int(*int as u64, false),
|
||||
Layout::Builtin(Builtin::Int8) => context.i8_type().const_int(*int as u64, false),
|
||||
|
|
|
@ -1273,7 +1273,7 @@ mod gen_list {
|
|||
app "quicksort" provides [ main ] to "./platform"
|
||||
|
||||
|
||||
swap : Int *, Int *, List a -> List a
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
|
@ -1396,7 +1396,7 @@ mod gen_list {
|
|||
quicksortHelp list 0 (n - 1)
|
||||
|
||||
|
||||
quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
|
@ -1408,7 +1408,7 @@ mod gen_list {
|
|||
list
|
||||
|
||||
|
||||
swap : Int *, Int *, List a -> List a
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
|
@ -1419,7 +1419,7 @@ mod gen_list {
|
|||
_ ->
|
||||
[]
|
||||
|
||||
partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
|
||||
partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
|
@ -1431,7 +1431,7 @@ mod gen_list {
|
|||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
|
@ -1466,7 +1466,7 @@ mod gen_list {
|
|||
quicksortHelp list 0 (List.len list - 1)
|
||||
|
||||
|
||||
quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
|
@ -1478,7 +1478,7 @@ mod gen_list {
|
|||
list
|
||||
|
||||
|
||||
swap : Int *, Int *, List a -> List a
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
|
@ -1489,7 +1489,7 @@ mod gen_list {
|
|||
_ ->
|
||||
[]
|
||||
|
||||
partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
|
||||
partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
|
@ -1501,7 +1501,7 @@ mod gen_list {
|
|||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Int *, Int *, List (Num a), Int *, Num a -> [ Pair (Int *) (List (Num a)) ]
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, Num a -> [ Pair Nat (List (Num a)) ]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
# if j < high then
|
||||
if False then
|
||||
|
@ -1539,7 +1539,7 @@ mod gen_list {
|
|||
quicksortHelp list 0 (List.len list - 1)
|
||||
|
||||
|
||||
quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
|
@ -1551,7 +1551,7 @@ mod gen_list {
|
|||
list
|
||||
|
||||
|
||||
swap : Int *, Int *, List a -> List a
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
|
@ -1562,7 +1562,7 @@ mod gen_list {
|
|||
_ ->
|
||||
[]
|
||||
|
||||
partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
|
||||
partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
|
@ -1574,7 +1574,7 @@ mod gen_list {
|
|||
Pair (low - 1) initialList
|
||||
|
||||
|
||||
partitionHelp : Int *, Int *, List (Num a), Int *, Num a -> [ Pair (Int *) (List (Num a)) ]
|
||||
partitionHelp : Nat, Nat, List (Num a), Nat, Num a -> [ Pair Nat (List (Num a)) ]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
|
@ -1740,6 +1740,7 @@ mod gen_list {
|
|||
assert_evals_to!("[[2]] != [[1]]", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
||||
fn cleanup_because_exception() {
|
||||
assert_evals_to!(
|
||||
|
|
|
@ -339,7 +339,7 @@ where
|
|||
Stmt::Ret(sym) => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
Stmt::Unreachable => {}
|
||||
Stmt::Rethrow => {}
|
||||
Stmt::Inc(sym, following) => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
self.scan_ast(following);
|
||||
|
|
|
@ -170,7 +170,7 @@ impl<'a> ParamMap<'a> {
|
|||
}
|
||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | Unreachable | Jump(_, _) | RuntimeError(_) => {
|
||||
Ret(_) | Rethrow | Jump(_, _) | RuntimeError(_) => {
|
||||
// these are terminal, do nothing
|
||||
}
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
}
|
||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | RuntimeError(_) | Unreachable => {
|
||||
Ret(_) | RuntimeError(_) | Rethrow => {
|
||||
// these are terminal, do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ pub enum Test<'a> {
|
|||
union: crate::exhaustive::Union,
|
||||
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
||||
},
|
||||
IsInt(i64),
|
||||
IsInt(i128),
|
||||
// float patterns are stored as u64 so they are comparable/hashable
|
||||
IsFloat(u64),
|
||||
IsStr(Box<str>),
|
||||
|
@ -445,10 +445,10 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V
|
|||
num_alts: union.alternatives.len(),
|
||||
});
|
||||
}
|
||||
IntLiteral(_, v) => {
|
||||
IntLiteral(v) => {
|
||||
all_tests.push(guarded(IsInt(*v)));
|
||||
}
|
||||
FloatLiteral(_, v) => {
|
||||
FloatLiteral(v) => {
|
||||
all_tests.push(IsFloat(*v));
|
||||
}
|
||||
StrLiteral(v) => {
|
||||
|
@ -636,7 +636,7 @@ fn to_relevant_branch_help<'a>(
|
|||
_ => None,
|
||||
},
|
||||
|
||||
IntLiteral(_, int) => match test {
|
||||
IntLiteral(int) => match test {
|
||||
IsInt(is_int) if int == *is_int => {
|
||||
start.extend(end);
|
||||
Some(Branch {
|
||||
|
@ -647,7 +647,7 @@ fn to_relevant_branch_help<'a>(
|
|||
_ => None,
|
||||
},
|
||||
|
||||
FloatLiteral(_, float) => match test {
|
||||
FloatLiteral(float) => match test {
|
||||
IsFloat(test_float) if float == *test_float => {
|
||||
start.extend(end);
|
||||
Some(Branch {
|
||||
|
@ -740,8 +740,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
|
|||
| AppliedTag { .. }
|
||||
| BitLiteral { .. }
|
||||
| EnumLiteral { .. }
|
||||
| IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
| IntLiteral(_)
|
||||
| FloatLiteral(_)
|
||||
| StrLiteral(_) => true,
|
||||
}
|
||||
}
|
||||
|
@ -1092,7 +1092,9 @@ fn test_to_equality<'a>(
|
|||
)
|
||||
}
|
||||
Test::IsInt(test_int) => {
|
||||
let lhs = Expr::Literal(Literal::Int(test_int));
|
||||
// TODO don't downcast i128 here
|
||||
debug_assert!(test_int <= i64::MAX as i128);
|
||||
let lhs = Expr::Literal(Literal::Int(test_int as i64));
|
||||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int64), lhs));
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ pub enum Pattern {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Literal {
|
||||
Int(i64),
|
||||
Int(i128),
|
||||
Bit(bool),
|
||||
Byte(u8),
|
||||
Float(u64),
|
||||
|
@ -48,8 +48,8 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
|
|||
use crate::ir::Pattern::*;
|
||||
|
||||
match pattern {
|
||||
IntLiteral(_, v) => Literal(Literal::Int(*v)),
|
||||
FloatLiteral(_, v) => Literal(Literal::Float(*v)),
|
||||
IntLiteral(v) => Literal(Literal::Int(*v)),
|
||||
FloatLiteral(v) => Literal(Literal::Float(*v)),
|
||||
StrLiteral(v) => Literal(Literal::Str(v.clone())),
|
||||
|
||||
// To make sure these are exhaustive, we have to "fake" a union here
|
||||
|
|
|
@ -50,7 +50,7 @@ pub fn occuring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>) {
|
|||
result.insert(*symbol);
|
||||
}
|
||||
|
||||
Unreachable => {}
|
||||
Rethrow => {}
|
||||
|
||||
Inc(symbol, cont) | Dec(symbol, cont) => {
|
||||
result.insert(*symbol);
|
||||
|
@ -792,7 +792,7 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Unreachable => (stmt, MutSet::default()),
|
||||
Rethrow => (stmt, MutSet::default()),
|
||||
|
||||
Jump(j, xs) => {
|
||||
let empty = MutSet::default();
|
||||
|
@ -953,7 +953,7 @@ pub fn collect_stmt(
|
|||
vars
|
||||
}
|
||||
|
||||
Unreachable => vars,
|
||||
Rethrow => vars,
|
||||
|
||||
RuntimeError(_) => vars,
|
||||
}
|
||||
|
|
|
@ -762,7 +762,7 @@ pub enum Stmt<'a> {
|
|||
ret_layout: Layout<'a>,
|
||||
},
|
||||
Ret(Symbol),
|
||||
Unreachable,
|
||||
Rethrow,
|
||||
Inc(Symbol, &'a Stmt<'a>),
|
||||
Dec(Symbol, &'a Stmt<'a>),
|
||||
Join {
|
||||
|
@ -911,11 +911,6 @@ pub enum CallType<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
// x = f a b c; S
|
||||
//
|
||||
//
|
||||
// invoke x = f a b c in S else Unreachable
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Expr<'a> {
|
||||
Literal(Literal<'a>),
|
||||
|
@ -1133,7 +1128,7 @@ impl<'a> Stmt<'a> {
|
|||
symbol,
|
||||
call,
|
||||
pass,
|
||||
fail: Stmt::Unreachable,
|
||||
fail: Stmt::Rethrow,
|
||||
..
|
||||
} => alloc
|
||||
.text("let ")
|
||||
|
@ -1166,7 +1161,7 @@ impl<'a> Stmt<'a> {
|
|||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(";"),
|
||||
|
||||
Unreachable => alloc.text("unreachable;"),
|
||||
Rethrow => alloc.text("unreachable;"),
|
||||
|
||||
Switch {
|
||||
cond_symbol,
|
||||
|
@ -4572,7 +4567,7 @@ fn substitute_in_stmt_help<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Unreachable => None,
|
||||
Rethrow => None,
|
||||
|
||||
RuntimeError(_) => None,
|
||||
}
|
||||
|
@ -4774,8 +4769,8 @@ fn store_pattern<'a>(
|
|||
Underscore => {
|
||||
// do nothing
|
||||
}
|
||||
IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
IntLiteral(_)
|
||||
| FloatLiteral(_)
|
||||
| EnumLiteral { .. }
|
||||
| BitLiteral { .. }
|
||||
| StrLiteral(_) => {}
|
||||
|
@ -4814,8 +4809,8 @@ fn store_pattern<'a>(
|
|||
Underscore => {
|
||||
// ignore
|
||||
}
|
||||
IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
IntLiteral(_)
|
||||
| FloatLiteral(_)
|
||||
| EnumLiteral { .. }
|
||||
| BitLiteral { .. }
|
||||
| StrLiteral(_) => {}
|
||||
|
@ -4909,8 +4904,8 @@ fn store_record_destruct<'a>(
|
|||
//
|
||||
// internally. But `y` is never used, so we must make sure it't not stored/loaded.
|
||||
}
|
||||
IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
IntLiteral(_)
|
||||
| FloatLiteral(_)
|
||||
| EnumLiteral { .. }
|
||||
| BitLiteral { .. }
|
||||
| StrLiteral(_) => {}
|
||||
|
@ -5293,7 +5288,7 @@ fn build_call<'a>(
|
|||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
if can_throw_exception(&call) {
|
||||
let fail = env.arena.alloc(Stmt::Unreachable);
|
||||
let fail = env.arena.alloc(Stmt::Rethrow);
|
||||
Stmt::Invoke {
|
||||
symbol: assigned,
|
||||
call,
|
||||
|
@ -5654,8 +5649,8 @@ fn call_by_name<'a>(
|
|||
pub enum Pattern<'a> {
|
||||
Identifier(Symbol),
|
||||
Underscore,
|
||||
IntLiteral(Variable, i64),
|
||||
FloatLiteral(Variable, u64),
|
||||
IntLiteral(i128),
|
||||
FloatLiteral(u64),
|
||||
BitLiteral {
|
||||
value: bool,
|
||||
tag_name: TagName,
|
||||
|
@ -5728,10 +5723,8 @@ fn from_can_pattern_help<'a>(
|
|||
match can_pattern {
|
||||
Underscore => Ok(Pattern::Underscore),
|
||||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||
IntLiteral(precision_var, int) => Ok(Pattern::IntLiteral(*precision_var, *int)),
|
||||
FloatLiteral(precision_var, float) => {
|
||||
Ok(Pattern::FloatLiteral(*precision_var, f64::to_bits(*float)))
|
||||
}
|
||||
IntLiteral(_, int) => Ok(Pattern::IntLiteral(*int as i128)),
|
||||
FloatLiteral(_, float) => Ok(Pattern::FloatLiteral(f64::to_bits(*float))),
|
||||
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
|
||||
Shadowed(region, ident) => Err(RuntimeError::Shadowing {
|
||||
original_region: *region,
|
||||
|
@ -5744,10 +5737,10 @@ fn from_can_pattern_help<'a>(
|
|||
}
|
||||
NumLiteral(var, num) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
|
||||
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
|
||||
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
|
||||
IntOrFloat::DecimalFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
|
||||
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
|
||||
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
|
||||
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
|
||||
IntOrFloat::DecimalFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ fn insert_jumps<'a>(
|
|||
pass: Stmt::Ret(rsym),
|
||||
..
|
||||
} if needle == *fsym && symbol == rsym => {
|
||||
debug_assert_eq!(fail, &&Stmt::Unreachable);
|
||||
debug_assert_eq!(fail, &&Stmt::Rethrow);
|
||||
|
||||
// replace the call and return with a jump
|
||||
|
||||
|
@ -237,7 +237,7 @@ fn insert_jumps<'a>(
|
|||
None => None,
|
||||
},
|
||||
|
||||
Unreachable => None,
|
||||
Rethrow => None,
|
||||
Ret(_) => None,
|
||||
Jump(_, _) => None,
|
||||
RuntimeError(_) => None,
|
||||
|
|
|
@ -66,6 +66,8 @@ cgmath = "0.17.0"
|
|||
itertools = "0.9.0"
|
||||
snafu = { version = "0.6", features = ["backtraces"] }
|
||||
colored = "2"
|
||||
pest = "2.1"
|
||||
pest_derive = "2.1"
|
||||
|
||||
|
||||
[dependencies.bytemuck]
|
||||
|
|
|
@ -55,8 +55,8 @@ These are potentially inspirational resources for the editor's design.
|
|||
### Productivity features
|
||||
|
||||
* When refactoring;
|
||||
- cutting and pasting code to a new file should automatically add imports to the new file and delete them from the old file.
|
||||
- When renaming a function for example, references in comments should be brought to the user's attention.
|
||||
- Cutting and pasting code to a new file should automatically add imports to the new file and delete them from the old file.
|
||||
- Ability to link e.g. variable name in comments to actual variable name. Comment is automatically updated when variable name is changed.
|
||||
* Automatically create all "arms" when pattern matching after entering `when var is` based on the type.
|
||||
- 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.
|
||||
|
||||
|
|
71
editor/src/graphics/lowlevel/pipelines.rs
Normal file
71
editor/src/graphics/lowlevel/pipelines.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use super::ortho::{init_ortho, OrthoResources};
|
||||
use super::vertex::Vertex;
|
||||
|
||||
pub struct RectResources {
|
||||
pub pipeline: wgpu::RenderPipeline,
|
||||
pub ortho: OrthoResources,
|
||||
}
|
||||
|
||||
pub fn make_rect_pipeline(
|
||||
gpu_device: &wgpu::Device,
|
||||
swap_chain_descr: &wgpu::SwapChainDescriptor,
|
||||
) -> RectResources {
|
||||
let ortho = init_ortho(swap_chain_descr.width, swap_chain_descr.height, gpu_device);
|
||||
|
||||
let pipeline_layout = gpu_device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&ortho.bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
label: Some("Rectangle pipeline layout"),
|
||||
});
|
||||
let pipeline = create_render_pipeline(
|
||||
&gpu_device,
|
||||
&pipeline_layout,
|
||||
swap_chain_descr.format,
|
||||
&[Vertex::DESC],
|
||||
wgpu::include_spirv!("../shaders/rect.vert.spv"),
|
||||
wgpu::include_spirv!("../shaders/rect.frag.spv"),
|
||||
);
|
||||
|
||||
RectResources { pipeline, ortho }
|
||||
}
|
||||
|
||||
pub fn create_render_pipeline(
|
||||
device: &wgpu::Device,
|
||||
layout: &wgpu::PipelineLayout,
|
||||
color_format: wgpu::TextureFormat,
|
||||
vertex_descs: &[wgpu::VertexBufferDescriptor],
|
||||
vs_src: wgpu::ShaderModuleSource,
|
||||
fs_src: wgpu::ShaderModuleSource,
|
||||
) -> wgpu::RenderPipeline {
|
||||
let vs_module = device.create_shader_module(vs_src);
|
||||
let fs_module = device.create_shader_module(fs_src);
|
||||
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render pipeline"),
|
||||
layout: Some(&layout),
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
}),
|
||||
rasterization_state: None,
|
||||
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
color_states: &[wgpu::ColorStateDescriptor {
|
||||
format: color_format,
|
||||
color_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
depth_stencil_state: None,
|
||||
sample_count: 1,
|
||||
sample_mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
vertex_state: wgpu::VertexStateDescriptor {
|
||||
index_format: wgpu::IndexFormat::Uint32,
|
||||
vertex_buffers: vertex_descs,
|
||||
},
|
||||
})
|
||||
}
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
// See this link to learn wgpu: https://sotrh.github.io/learn-wgpu/
|
||||
|
||||
extern crate pest;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
use crate::error::EdError::MissingGlyphDims;
|
||||
use crate::error::{print_err, EdResult};
|
||||
use crate::graphics::colors::{CARET_COLOR, CODE_COLOR, TXT_COLOR};
|
||||
|
|
File diff suppressed because it is too large
Load diff
52
editor/src/tea/ed_model.rs
Normal file
52
editor/src/tea/ed_model.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use crate::graphics::primitives::rect::Rect;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EdModel {
|
||||
pub lines: Vec<String>,
|
||||
pub caret_pos: Position,
|
||||
pub selection_opt: Option<RawSelection>,
|
||||
pub glyph_dim_rect_opt: Option<Rect>,
|
||||
}
|
||||
|
||||
pub fn init_model() -> EdModel {
|
||||
EdModel {
|
||||
lines: vec![String::new()],
|
||||
caret_pos: Position { line: 0, column: 0 },
|
||||
selection_opt: None,
|
||||
glyph_dim_rect_opt: None,
|
||||
}
|
||||
}
|
||||
|
||||
//Is model.rs the right place for these structs?
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Position {
|
||||
pub line: usize,
|
||||
pub column: usize,
|
||||
}
|
||||
|
||||
impl Ord for Position {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(self.line, self.column).cmp(&(other.line, other.column))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Position {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Position {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(self.line, self.column) == (other.line, other.column)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Position {}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RawSelection {
|
||||
pub start_pos: Position,
|
||||
pub end_pos: Position,
|
||||
}
|
|
@ -12,7 +12,12 @@ pub fn move_caret_left(
|
|||
let old_line_nr = old_caret_pos.line;
|
||||
let old_col_nr = old_caret_pos.column;
|
||||
|
||||
let (line_nr, col_nr) = if old_col_nr == 0 {
|
||||
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||
match old_selection_opt {
|
||||
Some(old_selection) => (old_selection.start_pos.line, old_selection.start_pos.column),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else if old_col_nr == 0 {
|
||||
if old_line_nr == 0 {
|
||||
(0, 0)
|
||||
} else if let Some(curr_line) = lines.get(old_line_nr - 1) {
|
||||
|
@ -31,6 +36,16 @@ pub fn move_caret_left(
|
|||
|
||||
let new_selection_opt = if shift_pressed {
|
||||
if let Some(old_selection) = old_selection_opt {
|
||||
if old_caret_pos >= old_selection.end_pos {
|
||||
if new_caret_pos == old_selection.start_pos {
|
||||
None
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: old_selection.start_pos,
|
||||
end_pos: new_caret_pos,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: Position {
|
||||
line: line_nr,
|
||||
|
@ -38,6 +53,7 @@ pub fn move_caret_left(
|
|||
},
|
||||
end_pos: old_selection.end_pos,
|
||||
})
|
||||
}
|
||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||
Some(RawSelection {
|
||||
start_pos: Position {
|
||||
|
@ -68,7 +84,12 @@ pub fn move_caret_right(
|
|||
let old_line_nr = old_caret_pos.line;
|
||||
let old_col_nr = old_caret_pos.column;
|
||||
|
||||
let (line_nr, col_nr) = if let Some(curr_line) = lines.get(old_line_nr) {
|
||||
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||
match old_selection_opt {
|
||||
Some(old_selection) => (old_selection.end_pos.line, old_selection.end_pos.column),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else if let Some(curr_line) = lines.get(old_line_nr) {
|
||||
if let Some(last_char) = curr_line.chars().last() {
|
||||
if is_newline(&last_char) {
|
||||
if old_col_nr + 1 > curr_line.len() - 1 {
|
||||
|
@ -95,6 +116,16 @@ pub fn move_caret_right(
|
|||
|
||||
let new_selection_opt = if shift_pressed {
|
||||
if let Some(old_selection) = old_selection_opt {
|
||||
if old_caret_pos <= old_selection.start_pos {
|
||||
if new_caret_pos == old_selection.end_pos {
|
||||
None
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: new_caret_pos,
|
||||
end_pos: old_selection.end_pos,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: old_selection.start_pos,
|
||||
end_pos: Position {
|
||||
|
@ -102,6 +133,7 @@ pub fn move_caret_right(
|
|||
column: col_nr,
|
||||
},
|
||||
})
|
||||
}
|
||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||
Some(RawSelection {
|
||||
start_pos: Position {
|
||||
|
@ -132,10 +164,15 @@ pub fn move_caret_up(
|
|||
let old_line_nr = old_caret_pos.line;
|
||||
let old_col_nr = old_caret_pos.column;
|
||||
|
||||
let (line_nr, col_nr) = if old_line_nr == 0 {
|
||||
(old_line_nr, old_col_nr)
|
||||
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||
match old_selection_opt {
|
||||
Some(old_selection) => (old_selection.start_pos.line, old_selection.start_pos.column),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else if old_line_nr == 0 {
|
||||
(old_line_nr, 0)
|
||||
} else if let Some(prev_line) = lines.get(old_line_nr - 1) {
|
||||
if prev_line.len() < old_col_nr {
|
||||
if prev_line.len() <= old_col_nr {
|
||||
(old_line_nr - 1, prev_line.len() - 1)
|
||||
} else {
|
||||
(old_line_nr - 1, old_col_nr)
|
||||
|
@ -151,10 +188,21 @@ pub fn move_caret_up(
|
|||
|
||||
let new_selection_opt = if shift_pressed {
|
||||
if let Some(old_selection) = old_selection_opt {
|
||||
if old_selection.end_pos <= old_caret_pos {
|
||||
if new_caret_pos == old_selection.start_pos {
|
||||
None
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: min(old_selection.start_pos, new_caret_pos),
|
||||
end_pos: max(old_selection.start_pos, new_caret_pos),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: new_caret_pos,
|
||||
end_pos: old_selection.end_pos,
|
||||
})
|
||||
}
|
||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||
Some(RawSelection {
|
||||
start_pos: min(old_caret_pos, new_caret_pos),
|
||||
|
@ -179,10 +227,19 @@ pub fn move_caret_down(
|
|||
let old_line_nr = old_caret_pos.line;
|
||||
let old_col_nr = old_caret_pos.column;
|
||||
|
||||
let (line_nr, col_nr) = if old_line_nr + 1 >= lines.len() {
|
||||
(old_line_nr, old_col_nr)
|
||||
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||
match old_selection_opt {
|
||||
Some(old_selection) => (old_selection.end_pos.line, old_selection.end_pos.column),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else if old_line_nr + 1 >= lines.len() {
|
||||
if let Some(curr_line) = lines.get(old_line_nr) {
|
||||
(old_line_nr, curr_line.len())
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else if let Some(next_line) = lines.get(old_line_nr + 1) {
|
||||
if next_line.len() < old_col_nr {
|
||||
if next_line.len() <= old_col_nr {
|
||||
if let Some(last_char) = next_line.chars().last() {
|
||||
if is_newline(&last_char) {
|
||||
(old_line_nr + 1, next_line.len() - 1)
|
||||
|
@ -206,10 +263,21 @@ pub fn move_caret_down(
|
|||
|
||||
let new_selection_opt = if shift_pressed {
|
||||
if let Some(old_selection) = old_selection_opt {
|
||||
if old_caret_pos <= old_selection.start_pos {
|
||||
if new_caret_pos == old_selection.end_pos {
|
||||
None
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: min(old_selection.end_pos, new_caret_pos),
|
||||
end_pos: max(old_selection.end_pos, new_caret_pos),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Some(RawSelection {
|
||||
start_pos: old_selection.start_pos,
|
||||
end_pos: new_caret_pos,
|
||||
})
|
||||
}
|
||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||
Some(RawSelection {
|
||||
start_pos: min(old_caret_pos, new_caret_pos),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub fn is_newline(char_ref: &char) -> bool {
|
||||
let newline_codes = vec!['\u{d}'];
|
||||
let newline_codes = vec!['\u{d}', '\n'];
|
||||
|
||||
newline_codes.contains(char_ref)
|
||||
}
|
||||
|
|
11
editor/tests/selection.pest
Normal file
11
editor/tests/selection.pest
Normal file
|
@ -0,0 +1,11 @@
|
|||
text = { (ASCII_ALPHANUMERIC | " " | "\t" | "\n")* }
|
||||
|
||||
caret = {"|"}
|
||||
|
||||
optSelStart = { "["{0,1} }
|
||||
|
||||
optSelEnd = { "]"{0,1} }
|
||||
|
||||
optCaret = { caret{0,1} }
|
||||
|
||||
linesWithSelect = { SOI ~ text ~ optCaret ~ text ~ optSelStart ~ text ~ optCaret ~ text ~ optCaret ~ text ~ optSelEnd ~ text ~ optCaret ~ text ~ EOI}
|
Loading…
Add table
Add a link
Reference in a new issue