mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +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",
|
"log",
|
||||||
"maplit",
|
"maplit",
|
||||||
"page_size",
|
"page_size",
|
||||||
|
"pest",
|
||||||
|
"pest_derive",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"quickcheck",
|
"quickcheck",
|
||||||
"quickcheck_macros",
|
"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>(
|
pub fn build_exp_literal<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout: &Layout<'_>,
|
layout: &Layout<'_>,
|
||||||
|
@ -492,22 +520,16 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
|
||||||
use roc_mono::ir::Literal::*;
|
use roc_mono::ir::Literal::*;
|
||||||
|
|
||||||
match literal {
|
match literal {
|
||||||
Int(int) =>
|
Int(int) => match layout {
|
||||||
(match layout {
|
Layout::Builtin(builtin) => int_with_precision(env, *int as i128, builtin).into(),
|
||||||
Layout::Builtin(Builtin::Usize) => ptr_int(env.context, env.ptr_bytes),
|
_ => panic!("Invalid layout for int literal = {:?}", layout),
|
||||||
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(),
|
Float(float) => match layout {
|
||||||
Layout::Builtin(Builtin::Int16) => env.context.i16_type(),
|
Layout::Builtin(builtin) => float_with_precision(env, *float, builtin).into(),
|
||||||
Layout::Builtin(Builtin::Int8) => env.context.i8_type(),
|
_ => panic!("Invalid layout for float literal = {:?}", layout),
|
||||||
_ => 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(),
|
|
||||||
_ => panic!("Invalid layout for float literal = {:?}", layout),
|
|
||||||
}).const_float(*num).into(),
|
|
||||||
Bool(b) => env.context.bool_type().const_int(*b as u64, false).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(),
|
Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(),
|
||||||
Str(str_literal) => {
|
Str(str_literal) => {
|
||||||
|
@ -1494,9 +1516,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
call,
|
call,
|
||||||
layout,
|
layout,
|
||||||
pass,
|
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
|
// so we can just treat this invoke as a normal call
|
||||||
let stmt =
|
let stmt =
|
||||||
roc_mono::ir::Stmt::Let(*symbol, Expr::Call(call.clone()), layout.clone(), pass);
|
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);
|
cxa_rethrow_exception(env);
|
||||||
|
|
||||||
// used in exception handling
|
// used in exception handling
|
||||||
|
@ -1783,6 +1805,22 @@ struct SwitchArgsIr<'a, 'ctx> {
|
||||||
pub ret_type: BasicTypeEnum<'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>(
|
fn build_switch_ir<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
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)
|
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::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::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::Int16) => context.i16_type().const_int(*int as u64, false),
|
||||||
Layout::Builtin(Builtin::Int8) => context.i8_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"
|
app "quicksort" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
swap : Int *, Int *, List a -> List a
|
swap : Nat, Nat, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
Pair (Ok atI) (Ok atJ) ->
|
Pair (Ok atI) (Ok atJ) ->
|
||||||
|
@ -1396,7 +1396,7 @@ mod gen_list {
|
||||||
quicksortHelp list 0 (n - 1)
|
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 ->
|
quicksortHelp = \list, low, high ->
|
||||||
if low < high then
|
if low < high then
|
||||||
when partition low high list is
|
when partition low high list is
|
||||||
|
@ -1408,7 +1408,7 @@ mod gen_list {
|
||||||
list
|
list
|
||||||
|
|
||||||
|
|
||||||
swap : Int *, Int *, List a -> List a
|
swap : Nat, Nat, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
Pair (Ok atI) (Ok atJ) ->
|
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 ->
|
partition = \low, high, initialList ->
|
||||||
when List.get initialList high is
|
when List.get initialList high is
|
||||||
Ok pivot ->
|
Ok pivot ->
|
||||||
|
@ -1431,7 +1431,7 @@ mod gen_list {
|
||||||
Pair (low - 1) initialList
|
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 ->
|
partitionHelp = \i, j, list, high, pivot ->
|
||||||
if j < high then
|
if j < high then
|
||||||
when List.get list j is
|
when List.get list j is
|
||||||
|
@ -1466,7 +1466,7 @@ mod gen_list {
|
||||||
quicksortHelp list 0 (List.len list - 1)
|
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 ->
|
quicksortHelp = \list, low, high ->
|
||||||
if low < high then
|
if low < high then
|
||||||
when partition low high list is
|
when partition low high list is
|
||||||
|
@ -1478,7 +1478,7 @@ mod gen_list {
|
||||||
list
|
list
|
||||||
|
|
||||||
|
|
||||||
swap : Int *, Int *, List a -> List a
|
swap : Nat, Nat, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
Pair (Ok atI) (Ok atJ) ->
|
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 ->
|
partition = \low, high, initialList ->
|
||||||
when List.get initialList high is
|
when List.get initialList high is
|
||||||
Ok pivot ->
|
Ok pivot ->
|
||||||
|
@ -1501,7 +1501,7 @@ mod gen_list {
|
||||||
Pair (low - 1) initialList
|
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 ->
|
partitionHelp = \i, j, list, high, pivot ->
|
||||||
# if j < high then
|
# if j < high then
|
||||||
if False then
|
if False then
|
||||||
|
@ -1539,7 +1539,7 @@ mod gen_list {
|
||||||
quicksortHelp list 0 (List.len list - 1)
|
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 ->
|
quicksortHelp = \list, low, high ->
|
||||||
if low < high then
|
if low < high then
|
||||||
when partition low high list is
|
when partition low high list is
|
||||||
|
@ -1551,7 +1551,7 @@ mod gen_list {
|
||||||
list
|
list
|
||||||
|
|
||||||
|
|
||||||
swap : Int *, Int *, List a -> List a
|
swap : Nat, Nat, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
Pair (Ok atI) (Ok atJ) ->
|
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 ->
|
partition = \low, high, initialList ->
|
||||||
when List.get initialList high is
|
when List.get initialList high is
|
||||||
Ok pivot ->
|
Ok pivot ->
|
||||||
|
@ -1574,7 +1574,7 @@ mod gen_list {
|
||||||
Pair (low - 1) initialList
|
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 ->
|
partitionHelp = \i, j, list, high, pivot ->
|
||||||
if j < high then
|
if j < high then
|
||||||
when List.get list j is
|
when List.get list j is
|
||||||
|
@ -1740,6 +1740,7 @@ mod gen_list {
|
||||||
assert_evals_to!("[[2]] != [[1]]", true, bool);
|
assert_evals_to!("[[2]] != [[1]]", true, bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
#[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
|
||||||
fn cleanup_because_exception() {
|
fn cleanup_because_exception() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
|
|
@ -339,7 +339,7 @@ where
|
||||||
Stmt::Ret(sym) => {
|
Stmt::Ret(sym) => {
|
||||||
self.set_last_seen(*sym, stmt);
|
self.set_last_seen(*sym, stmt);
|
||||||
}
|
}
|
||||||
Stmt::Unreachable => {}
|
Stmt::Rethrow => {}
|
||||||
Stmt::Inc(sym, following) => {
|
Stmt::Inc(sym, following) => {
|
||||||
self.set_last_seen(*sym, stmt);
|
self.set_last_seen(*sym, stmt);
|
||||||
self.scan_ast(following);
|
self.scan_ast(following);
|
||||||
|
|
|
@ -170,7 +170,7 @@ impl<'a> ParamMap<'a> {
|
||||||
}
|
}
|
||||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||||
|
|
||||||
Ret(_) | Unreachable | Jump(_, _) | RuntimeError(_) => {
|
Ret(_) | Rethrow | Jump(_, _) | RuntimeError(_) => {
|
||||||
// these are terminal, do nothing
|
// these are terminal, do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +515,7 @@ impl<'a> BorrowInfState<'a> {
|
||||||
}
|
}
|
||||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||||
|
|
||||||
Ret(_) | RuntimeError(_) | Unreachable => {
|
Ret(_) | RuntimeError(_) | Rethrow => {
|
||||||
// these are terminal, do nothing
|
// these are terminal, do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub enum Test<'a> {
|
||||||
union: crate::exhaustive::Union,
|
union: crate::exhaustive::Union,
|
||||||
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
||||||
},
|
},
|
||||||
IsInt(i64),
|
IsInt(i128),
|
||||||
// float patterns are stored as u64 so they are comparable/hashable
|
// float patterns are stored as u64 so they are comparable/hashable
|
||||||
IsFloat(u64),
|
IsFloat(u64),
|
||||||
IsStr(Box<str>),
|
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(),
|
num_alts: union.alternatives.len(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IntLiteral(_, v) => {
|
IntLiteral(v) => {
|
||||||
all_tests.push(guarded(IsInt(*v)));
|
all_tests.push(guarded(IsInt(*v)));
|
||||||
}
|
}
|
||||||
FloatLiteral(_, v) => {
|
FloatLiteral(v) => {
|
||||||
all_tests.push(IsFloat(*v));
|
all_tests.push(IsFloat(*v));
|
||||||
}
|
}
|
||||||
StrLiteral(v) => {
|
StrLiteral(v) => {
|
||||||
|
@ -636,7 +636,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
IntLiteral(_, int) => match test {
|
IntLiteral(int) => match test {
|
||||||
IsInt(is_int) if int == *is_int => {
|
IsInt(is_int) if int == *is_int => {
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
|
@ -647,7 +647,7 @@ fn to_relevant_branch_help<'a>(
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
FloatLiteral(_, float) => match test {
|
FloatLiteral(float) => match test {
|
||||||
IsFloat(test_float) if float == *test_float => {
|
IsFloat(test_float) if float == *test_float => {
|
||||||
start.extend(end);
|
start.extend(end);
|
||||||
Some(Branch {
|
Some(Branch {
|
||||||
|
@ -740,8 +740,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
|
||||||
| AppliedTag { .. }
|
| AppliedTag { .. }
|
||||||
| BitLiteral { .. }
|
| BitLiteral { .. }
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
| IntLiteral(_, _)
|
| IntLiteral(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_)
|
||||||
| StrLiteral(_) => true,
|
| StrLiteral(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1092,9 @@ fn test_to_equality<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Test::IsInt(test_int) => {
|
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();
|
let lhs_symbol = env.unique_symbol();
|
||||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int64), lhs));
|
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int64), lhs));
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub enum Pattern {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Int(i64),
|
Int(i128),
|
||||||
Bit(bool),
|
Bit(bool),
|
||||||
Byte(u8),
|
Byte(u8),
|
||||||
Float(u64),
|
Float(u64),
|
||||||
|
@ -48,8 +48,8 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
|
||||||
use crate::ir::Pattern::*;
|
use crate::ir::Pattern::*;
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
IntLiteral(_, v) => Literal(Literal::Int(*v)),
|
IntLiteral(v) => Literal(Literal::Int(*v)),
|
||||||
FloatLiteral(_, v) => Literal(Literal::Float(*v)),
|
FloatLiteral(v) => Literal(Literal::Float(*v)),
|
||||||
StrLiteral(v) => Literal(Literal::Str(v.clone())),
|
StrLiteral(v) => Literal(Literal::Str(v.clone())),
|
||||||
|
|
||||||
// To make sure these are exhaustive, we have to "fake" a union here
|
// 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);
|
result.insert(*symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => {}
|
Rethrow => {}
|
||||||
|
|
||||||
Inc(symbol, cont) | Dec(symbol, cont) => {
|
Inc(symbol, cont) | Dec(symbol, cont) => {
|
||||||
result.insert(*symbol);
|
result.insert(*symbol);
|
||||||
|
@ -792,7 +792,7 @@ impl<'a> Context<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => (stmt, MutSet::default()),
|
Rethrow => (stmt, MutSet::default()),
|
||||||
|
|
||||||
Jump(j, xs) => {
|
Jump(j, xs) => {
|
||||||
let empty = MutSet::default();
|
let empty = MutSet::default();
|
||||||
|
@ -953,7 +953,7 @@ pub fn collect_stmt(
|
||||||
vars
|
vars
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => vars,
|
Rethrow => vars,
|
||||||
|
|
||||||
RuntimeError(_) => vars,
|
RuntimeError(_) => vars,
|
||||||
}
|
}
|
||||||
|
|
|
@ -762,7 +762,7 @@ pub enum Stmt<'a> {
|
||||||
ret_layout: Layout<'a>,
|
ret_layout: Layout<'a>,
|
||||||
},
|
},
|
||||||
Ret(Symbol),
|
Ret(Symbol),
|
||||||
Unreachable,
|
Rethrow,
|
||||||
Inc(Symbol, &'a Stmt<'a>),
|
Inc(Symbol, &'a Stmt<'a>),
|
||||||
Dec(Symbol, &'a Stmt<'a>),
|
Dec(Symbol, &'a Stmt<'a>),
|
||||||
Join {
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
Literal(Literal<'a>),
|
Literal(Literal<'a>),
|
||||||
|
@ -1133,7 +1128,7 @@ impl<'a> Stmt<'a> {
|
||||||
symbol,
|
symbol,
|
||||||
call,
|
call,
|
||||||
pass,
|
pass,
|
||||||
fail: Stmt::Unreachable,
|
fail: Stmt::Rethrow,
|
||||||
..
|
..
|
||||||
} => alloc
|
} => alloc
|
||||||
.text("let ")
|
.text("let ")
|
||||||
|
@ -1166,7 +1161,7 @@ impl<'a> Stmt<'a> {
|
||||||
.append(symbol_to_doc(alloc, *symbol))
|
.append(symbol_to_doc(alloc, *symbol))
|
||||||
.append(";"),
|
.append(";"),
|
||||||
|
|
||||||
Unreachable => alloc.text("unreachable;"),
|
Rethrow => alloc.text("unreachable;"),
|
||||||
|
|
||||||
Switch {
|
Switch {
|
||||||
cond_symbol,
|
cond_symbol,
|
||||||
|
@ -4572,7 +4567,7 @@ fn substitute_in_stmt_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => None,
|
Rethrow => None,
|
||||||
|
|
||||||
RuntimeError(_) => None,
|
RuntimeError(_) => None,
|
||||||
}
|
}
|
||||||
|
@ -4774,8 +4769,8 @@ fn store_pattern<'a>(
|
||||||
Underscore => {
|
Underscore => {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
IntLiteral(_, _)
|
IntLiteral(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_)
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
| BitLiteral { .. }
|
| BitLiteral { .. }
|
||||||
| StrLiteral(_) => {}
|
| StrLiteral(_) => {}
|
||||||
|
@ -4814,8 +4809,8 @@ fn store_pattern<'a>(
|
||||||
Underscore => {
|
Underscore => {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
IntLiteral(_, _)
|
IntLiteral(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_)
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
| BitLiteral { .. }
|
| BitLiteral { .. }
|
||||||
| StrLiteral(_) => {}
|
| 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.
|
// internally. But `y` is never used, so we must make sure it't not stored/loaded.
|
||||||
}
|
}
|
||||||
IntLiteral(_, _)
|
IntLiteral(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_)
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
| BitLiteral { .. }
|
| BitLiteral { .. }
|
||||||
| StrLiteral(_) => {}
|
| StrLiteral(_) => {}
|
||||||
|
@ -5293,7 +5288,7 @@ fn build_call<'a>(
|
||||||
hole: &'a Stmt<'a>,
|
hole: &'a Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
if can_throw_exception(&call) {
|
if can_throw_exception(&call) {
|
||||||
let fail = env.arena.alloc(Stmt::Unreachable);
|
let fail = env.arena.alloc(Stmt::Rethrow);
|
||||||
Stmt::Invoke {
|
Stmt::Invoke {
|
||||||
symbol: assigned,
|
symbol: assigned,
|
||||||
call,
|
call,
|
||||||
|
@ -5654,8 +5649,8 @@ fn call_by_name<'a>(
|
||||||
pub enum Pattern<'a> {
|
pub enum Pattern<'a> {
|
||||||
Identifier(Symbol),
|
Identifier(Symbol),
|
||||||
Underscore,
|
Underscore,
|
||||||
IntLiteral(Variable, i64),
|
IntLiteral(i128),
|
||||||
FloatLiteral(Variable, u64),
|
FloatLiteral(u64),
|
||||||
BitLiteral {
|
BitLiteral {
|
||||||
value: bool,
|
value: bool,
|
||||||
tag_name: TagName,
|
tag_name: TagName,
|
||||||
|
@ -5728,10 +5723,8 @@ fn from_can_pattern_help<'a>(
|
||||||
match can_pattern {
|
match can_pattern {
|
||||||
Underscore => Ok(Pattern::Underscore),
|
Underscore => Ok(Pattern::Underscore),
|
||||||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||||
IntLiteral(precision_var, int) => Ok(Pattern::IntLiteral(*precision_var, *int)),
|
IntLiteral(_, int) => Ok(Pattern::IntLiteral(*int as i128)),
|
||||||
FloatLiteral(precision_var, float) => {
|
FloatLiteral(_, float) => Ok(Pattern::FloatLiteral(f64::to_bits(*float))),
|
||||||
Ok(Pattern::FloatLiteral(*precision_var, f64::to_bits(*float)))
|
|
||||||
}
|
|
||||||
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
|
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
|
||||||
Shadowed(region, ident) => Err(RuntimeError::Shadowing {
|
Shadowed(region, ident) => Err(RuntimeError::Shadowing {
|
||||||
original_region: *region,
|
original_region: *region,
|
||||||
|
@ -5744,10 +5737,10 @@ fn from_can_pattern_help<'a>(
|
||||||
}
|
}
|
||||||
NumLiteral(var, num) => {
|
NumLiteral(var, num) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||||
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
|
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
|
||||||
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
|
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
|
||||||
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
|
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
|
||||||
IntOrFloat::DecimalFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
|
IntOrFloat::DecimalFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ fn insert_jumps<'a>(
|
||||||
pass: Stmt::Ret(rsym),
|
pass: Stmt::Ret(rsym),
|
||||||
..
|
..
|
||||||
} if needle == *fsym && symbol == 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
|
// replace the call and return with a jump
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ fn insert_jumps<'a>(
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
Unreachable => None,
|
Rethrow => None,
|
||||||
Ret(_) => None,
|
Ret(_) => None,
|
||||||
Jump(_, _) => None,
|
Jump(_, _) => None,
|
||||||
RuntimeError(_) => None,
|
RuntimeError(_) => None,
|
||||||
|
|
|
@ -66,6 +66,8 @@ cgmath = "0.17.0"
|
||||||
itertools = "0.9.0"
|
itertools = "0.9.0"
|
||||||
snafu = { version = "0.6", features = ["backtraces"] }
|
snafu = { version = "0.6", features = ["backtraces"] }
|
||||||
colored = "2"
|
colored = "2"
|
||||||
|
pest = "2.1"
|
||||||
|
pest_derive = "2.1"
|
||||||
|
|
||||||
|
|
||||||
[dependencies.bytemuck]
|
[dependencies.bytemuck]
|
||||||
|
|
|
@ -55,8 +55,8 @@ These are potentially inspirational resources for the editor's design.
|
||||||
### Productivity features
|
### Productivity features
|
||||||
|
|
||||||
* When refactoring;
|
* 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.
|
- 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.
|
- 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.
|
* 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.
|
- 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/
|
// 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::EdError::MissingGlyphDims;
|
||||||
use crate::error::{print_err, EdResult};
|
use crate::error::{print_err, EdResult};
|
||||||
use crate::graphics::colors::{CARET_COLOR, CODE_COLOR, TXT_COLOR};
|
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_line_nr = old_caret_pos.line;
|
||||||
let old_col_nr = old_caret_pos.column;
|
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 {
|
if old_line_nr == 0 {
|
||||||
(0, 0)
|
(0, 0)
|
||||||
} else if let Some(curr_line) = lines.get(old_line_nr - 1) {
|
} else if let Some(curr_line) = lines.get(old_line_nr - 1) {
|
||||||
|
@ -31,13 +36,24 @@ pub fn move_caret_left(
|
||||||
|
|
||||||
let new_selection_opt = if shift_pressed {
|
let new_selection_opt = if shift_pressed {
|
||||||
if let Some(old_selection) = old_selection_opt {
|
if let Some(old_selection) = old_selection_opt {
|
||||||
Some(RawSelection {
|
if old_caret_pos >= old_selection.end_pos {
|
||||||
start_pos: Position {
|
if new_caret_pos == old_selection.start_pos {
|
||||||
line: line_nr,
|
None
|
||||||
column: col_nr,
|
} else {
|
||||||
},
|
Some(RawSelection {
|
||||||
end_pos: old_selection.end_pos,
|
start_pos: old_selection.start_pos,
|
||||||
})
|
end_pos: new_caret_pos,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some(RawSelection {
|
||||||
|
start_pos: Position {
|
||||||
|
line: line_nr,
|
||||||
|
column: col_nr,
|
||||||
|
},
|
||||||
|
end_pos: old_selection.end_pos,
|
||||||
|
})
|
||||||
|
}
|
||||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||||
Some(RawSelection {
|
Some(RawSelection {
|
||||||
start_pos: Position {
|
start_pos: Position {
|
||||||
|
@ -68,7 +84,12 @@ pub fn move_caret_right(
|
||||||
let old_line_nr = old_caret_pos.line;
|
let old_line_nr = old_caret_pos.line;
|
||||||
let old_col_nr = old_caret_pos.column;
|
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 let Some(last_char) = curr_line.chars().last() {
|
||||||
if is_newline(&last_char) {
|
if is_newline(&last_char) {
|
||||||
if old_col_nr + 1 > curr_line.len() - 1 {
|
if old_col_nr + 1 > curr_line.len() - 1 {
|
||||||
|
@ -95,13 +116,24 @@ pub fn move_caret_right(
|
||||||
|
|
||||||
let new_selection_opt = if shift_pressed {
|
let new_selection_opt = if shift_pressed {
|
||||||
if let Some(old_selection) = old_selection_opt {
|
if let Some(old_selection) = old_selection_opt {
|
||||||
Some(RawSelection {
|
if old_caret_pos <= old_selection.start_pos {
|
||||||
start_pos: old_selection.start_pos,
|
if new_caret_pos == old_selection.end_pos {
|
||||||
end_pos: Position {
|
None
|
||||||
line: line_nr,
|
} else {
|
||||||
column: col_nr,
|
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 {
|
||||||
|
line: line_nr,
|
||||||
|
column: col_nr,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||||
Some(RawSelection {
|
Some(RawSelection {
|
||||||
start_pos: Position {
|
start_pos: Position {
|
||||||
|
@ -132,10 +164,15 @@ pub fn move_caret_up(
|
||||||
let old_line_nr = old_caret_pos.line;
|
let old_line_nr = old_caret_pos.line;
|
||||||
let old_col_nr = old_caret_pos.column;
|
let old_col_nr = old_caret_pos.column;
|
||||||
|
|
||||||
let (line_nr, col_nr) = if old_line_nr == 0 {
|
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||||
(old_line_nr, old_col_nr)
|
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) {
|
} 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)
|
(old_line_nr - 1, prev_line.len() - 1)
|
||||||
} else {
|
} else {
|
||||||
(old_line_nr - 1, old_col_nr)
|
(old_line_nr - 1, old_col_nr)
|
||||||
|
@ -151,10 +188,21 @@ pub fn move_caret_up(
|
||||||
|
|
||||||
let new_selection_opt = if shift_pressed {
|
let new_selection_opt = if shift_pressed {
|
||||||
if let Some(old_selection) = old_selection_opt {
|
if let Some(old_selection) = old_selection_opt {
|
||||||
Some(RawSelection {
|
if old_selection.end_pos <= old_caret_pos {
|
||||||
start_pos: new_caret_pos,
|
if new_caret_pos == old_selection.start_pos {
|
||||||
end_pos: old_selection.end_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) {
|
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||||
Some(RawSelection {
|
Some(RawSelection {
|
||||||
start_pos: min(old_caret_pos, new_caret_pos),
|
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_line_nr = old_caret_pos.line;
|
||||||
let old_col_nr = old_caret_pos.column;
|
let old_col_nr = old_caret_pos.column;
|
||||||
|
|
||||||
let (line_nr, col_nr) = if old_line_nr + 1 >= lines.len() {
|
let (line_nr, col_nr) = if old_selection_opt.is_some() && !shift_pressed {
|
||||||
(old_line_nr, old_col_nr)
|
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) {
|
} 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 let Some(last_char) = next_line.chars().last() {
|
||||||
if is_newline(&last_char) {
|
if is_newline(&last_char) {
|
||||||
(old_line_nr + 1, next_line.len() - 1)
|
(old_line_nr + 1, next_line.len() - 1)
|
||||||
|
@ -206,10 +263,21 @@ pub fn move_caret_down(
|
||||||
|
|
||||||
let new_selection_opt = if shift_pressed {
|
let new_selection_opt = if shift_pressed {
|
||||||
if let Some(old_selection) = old_selection_opt {
|
if let Some(old_selection) = old_selection_opt {
|
||||||
Some(RawSelection {
|
if old_caret_pos <= old_selection.start_pos {
|
||||||
start_pos: old_selection.start_pos,
|
if new_caret_pos == old_selection.end_pos {
|
||||||
end_pos: new_caret_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) {
|
} else if !(old_line_nr == line_nr && old_col_nr == col_nr) {
|
||||||
Some(RawSelection {
|
Some(RawSelection {
|
||||||
start_pos: min(old_caret_pos, new_caret_pos),
|
start_pos: min(old_caret_pos, new_caret_pos),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub fn is_newline(char_ref: &char) -> bool {
|
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)
|
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