Skip to content

Commit 9139ae8

Browse files
committed
parse subscript numbers that are too large
1 parent cc0e504 commit 9139ae8

File tree

9 files changed

+59
-39
lines changed

9 files changed

+59
-39
lines changed

pad/editor/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,21 +2337,21 @@ fn modifier_class(margs: usize) -> &'static str {
23372337
}
23382338
}
23392339

2340-
fn prim_sig_class(prim: Primitive, subscript: Option<Subscript>) -> &'static str {
2340+
fn prim_sig_class(prim: Primitive, subscript: Option<&Subscript>) -> &'static str {
23412341
match prim {
23422342
Primitive::Identity => code_font!("stack-function"),
23432343
Primitive::Transpose if at_least_a_little_gay() => {
23442344
code_font!("monadic-function trans text-gradient")
23452345
}
23462346
Primitive::Both if at_least_a_little_gay() => {
2347-
match subscript.as_ref().and_then(Subscript::n).unwrap_or(2) {
2347+
match subscript.and_then(Subscript::n).unwrap_or(2) {
23482348
0 => code_font!("monadic-function aroace text-gradient"),
23492349
1 => code_font!("monadic-function aro text-gradient"),
23502350
2 => code_font!("monadic-modifier bi text-gradient"),
23512351
_ => code_font!("dyadic-function pan text-gradient"),
23522352
}
23532353
}
2354-
Primitive::Couple => match subscript.as_ref().and_then(Subscript::n).unwrap_or(2) {
2354+
Primitive::Couple => match subscript.and_then(Subscript::n).unwrap_or(2) {
23552355
0 if at_least_a_little_gay() => {
23562356
code_font!("monadic-function aroace text-gradient")
23572357
}

pad/editor/src/utils.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,9 @@ pub fn gen_code_view(id: &str, code: &str) -> View {
664664
CodeFragment::Br => frag_views.push(view! { <br /> }.into_view()),
665665
CodeFragment::Span(text, kind) => {
666666
let color_class = match &kind {
667-
SpanKind::Primitive(prim, sig) => prim_sig_class(*prim, *sig),
667+
SpanKind::Primitive(prim, subscript) => {
668+
prim_sig_class(*prim, subscript.as_ref())
669+
}
668670
SpanKind::Obverse(_) => prim_sig_class(Primitive::Obverse, None),
669671
SpanKind::Number if very_gay() => "text-gradient number-lesbian",
670672
SpanKind::Number => "number-literal",
@@ -678,7 +680,7 @@ pub fn gen_code_view(id: &str, code: &str) -> View {
678680
SpanKind::Comment | SpanKind::OutputComment => "comment-span",
679681
SpanKind::Strand => "strand-span",
680682
SpanKind::Subscript(None, _) => "number-literal",
681-
SpanKind::Subscript(Some(prim), n) => prim_sig_class(*prim, *n),
683+
SpanKind::Subscript(Some(prim), n) => prim_sig_class(*prim, n.as_ref()),
682684
SpanKind::MacroDelim(margs) => modifier_class(*margs),
683685
SpanKind::ArgSetter(_) => sig_class((1, 0).into()),
684686
_ => "",
@@ -747,7 +749,7 @@ pub fn gen_code_view(id: &str, code: &str) -> View {
747749
else {
748750
unreachable!()
749751
};
750-
let next_color_class = prim_sig_class(next_prim, next_sig);
752+
let next_color_class = prim_sig_class(next_prim, next_sig.as_ref());
751753
let title =
752754
PAIR_ALIASES.with(|map| *map.get(&(prim, next_prim)).unwrap());
753755
let title = format!("(compound) {title}");

parser/src/lex.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ impl Token {
688688
}
689689
pub(crate) fn as_subscript(&self) -> Option<Subscript> {
690690
match self {
691-
Token::Subscr(n) => Some(*n),
691+
Token::Subscr(sub) => Some(sub.clone()),
692692
_ => None,
693693
}
694694
}
@@ -1429,6 +1429,7 @@ impl<'a> Lexer<'a> {
14291429
can_parse_ascii: &mut bool,
14301430
got_neg: &mut bool,
14311431
too_large: &mut bool,
1432+
s: &mut EcoString,
14321433
num: &mut Option<i32>,
14331434
) {
14341435
loop {
@@ -1438,16 +1439,19 @@ impl<'a> Lexer<'a> {
14381439
|| *can_parse_ascii && (self.next_char_exact("`") || self.next_char_exact("¯")))
14391440
{
14401441
*got_neg = true;
1442+
s.push('¯');
14411443
} else if let Some(c) = can_parse_ascii
14421444
.then(|| self.next_char_if_all(|c| c.is_ascii_digit()))
14431445
.flatten()
14441446
{
14451447
let num = num.get_or_insert(0);
14461448
let (new_num, overflow) = num.overflowing_mul(10);
14471449
*too_large |= overflow;
1448-
let (new_num, overflow) = new_num.overflowing_add(c.parse::<i32>().unwrap());
1450+
let n = c.parse::<i32>().unwrap();
1451+
let (new_num, overflow) = new_num.overflowing_add(n);
14491452
*too_large |= overflow;
14501453
*num = new_num;
1454+
s.push(char::from_u32('₀' as u32 + n as u32).unwrap());
14511455
} else if let Some(c) = self.next_char_if_all(|c| SUBSCRIPT_DIGITS.contains(&c)) {
14521456
let i = SUBSCRIPT_DIGITS
14531457
.iter()
@@ -1460,6 +1464,7 @@ impl<'a> Lexer<'a> {
14601464
*too_large |= overflow;
14611465
*num = new_num;
14621466
*can_parse_ascii = false;
1467+
s.push_str(c);
14631468
} else if self.next_chars_exact(["_"; 2]) || self.next_char_exact(",") {
14641469
*can_parse_ascii = true;
14651470
} else {
@@ -1474,22 +1479,31 @@ impl<'a> Lexer<'a> {
14741479
let mut num = None;
14751480
let mut side = None;
14761481
let mut side_num = None;
1482+
let mut n_str = EcoString::new();
14771483
match init {
14781484
"⌞" => side = Some(SubSide::Left),
14791485
"⌟" => side = Some(SubSide::Right),
14801486
"₋" => got_neg = true,
14811487
"__" | "," => can_parse_ascii = true,
14821488
c if c.chars().all(|c| SUBSCRIPT_DIGITS.contains(&c)) => {
1483-
num = SUBSCRIPT_DIGITS
1484-
.iter()
1489+
let n = (SUBSCRIPT_DIGITS.iter())
14851490
.position(|&d| d == c.chars().next().unwrap())
1486-
.map(|i| i as i32);
1491+
.map(|i| i as i32)
1492+
.unwrap();
1493+
num = Some(n);
1494+
n_str.push_str(c);
14871495
}
14881496
_ => {}
14891497
}
14901498
// Parse number
14911499
if side.is_none() {
1492-
self.sub_num(&mut can_parse_ascii, &mut got_neg, &mut too_large, &mut num);
1500+
self.sub_num(
1501+
&mut can_parse_ascii,
1502+
&mut got_neg,
1503+
&mut too_large,
1504+
&mut n_str,
1505+
&mut num,
1506+
);
14931507
}
14941508
// Parse side
14951509
if side.is_none() {
@@ -1510,6 +1524,7 @@ impl<'a> Lexer<'a> {
15101524
&mut can_parse_ascii,
15111525
&mut true,
15121526
&mut too_large,
1527+
&mut EcoString::new(),
15131528
&mut side_num,
15141529
);
15151530
if too_large {
@@ -1518,7 +1533,7 @@ impl<'a> Lexer<'a> {
15181533
}
15191534
Subscript {
15201535
num: if too_large {
1521-
Some(NumericSubscript::TooLarge)
1536+
Some(NumericSubscript::TooLarge(n_str))
15221537
} else if let Some(mut n) = num {
15231538
if got_neg {
15241539
n = -n;

parser/src/primitive.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ impl Primitive {
229229
FormatPrimitive(*self)
230230
}
231231
/// The modified signature of the primitive given a subscript
232-
pub fn subscript_sig(&self, sub: Option<Subscript>) -> Option<Signature> {
232+
pub fn subscript_sig(&self, sub: Option<&Subscript>) -> Option<Signature> {
233233
use Primitive::*;
234234
let sub = sub?;
235-
let n = match sub.num? {
236-
NumericSubscript::N(n) => Some(n),
235+
let n = match sub.num.as_ref()? {
236+
NumericSubscript::N(n) => Some(*n),
237237
_ => None,
238238
};
239239
Some(match (self, n) {

parser/src/subscript.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::fmt;
22

3+
use ecow::EcoString;
34
use serde::*;
45

56
use crate::SUBSCRIPT_DIGITS;
@@ -35,13 +36,13 @@ impl From<i32> for Subscript {
3536
}
3637

3738
/// The numeric part of a subscript
38-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3940
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
4041
pub enum NumericSubscript {
4142
/// Only a negative sign
4243
NegOnly,
4344
/// The number is too large to be represented
44-
TooLarge,
45+
TooLarge(EcoString),
4546
/// A valid number
4647
#[serde(untagged)]
4748
N(i32),
@@ -85,8 +86,8 @@ impl Subscript {
8586
}
8687
/// Get the numeric part of the subscript as an integer, if it exists
8788
pub fn n(&self) -> Option<i32> {
88-
self.num.and_then(|n| match n {
89-
NumericSubscript::N(n) => Some(n),
89+
self.num.as_ref().and_then(|n| match n {
90+
NumericSubscript::N(n) => Some(*n),
9091
_ => None,
9192
})
9293
}
@@ -124,7 +125,7 @@ impl fmt::Display for NumericSubscript {
124125
}
125126
Ok(())
126127
}
127-
NumericSubscript::TooLarge => write!(f, "…"),
128+
NumericSubscript::TooLarge(s) => s.fmt(f),
128129
}
129130
}
130131
}

src/compile/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,7 +2268,7 @@ impl Compiler {
22682268
match prim {
22692269
prim if prim.sig().is_some_and(|sig| sig == (2, 1))
22702270
&& prim
2271-
.subscript_sig(Some(Subscript::numeric(2)))
2271+
.subscript_sig(Some(&Subscript::numeric(2)))
22722272
.is_some_and(|sig| sig == (1, 1)) =>
22732273
{
22742274
Node::from_iter([Node::new_push(n), self.primitive(prim, span)])
@@ -2480,20 +2480,20 @@ impl<N: PartialEq> PartialEq<N> for SubNOrSide<N> {
24802480
impl Compiler {
24812481
fn validate_subscript(&mut self, sub: Sp<Subscript>) -> Sp<Subscript<i32>> {
24822482
let side = sub.value.side;
2483-
let num = (sub.value.num).and_then(|num| self.numeric_subscript_n(num, &sub.span));
2483+
let num = (sub.value.num.as_ref()).and_then(|num| self.numeric_subscript_n(num, &sub.span));
24842484
if num.is_none() && side.is_none() {
24852485
self.add_error(sub.span.clone(), "Subscript is incomplete");
24862486
}
24872487
sub.span.sp(Subscript { num, side })
24882488
}
2489-
fn numeric_subscript_n(&mut self, num: NumericSubscript, span: &CodeSpan) -> Option<i32> {
2489+
fn numeric_subscript_n(&mut self, num: &NumericSubscript, span: &CodeSpan) -> Option<i32> {
24902490
match num {
2491-
NumericSubscript::N(n) => Some(n),
2491+
NumericSubscript::N(n) => Some(*n),
24922492
NumericSubscript::NegOnly => {
24932493
self.add_error(span.clone(), "Subscript is incomplete");
24942494
None
24952495
}
2496-
NumericSubscript::TooLarge => {
2496+
NumericSubscript::TooLarge(_) => {
24972497
self.add_error(span.clone(), "Subscript is too large");
24982498
None
24992499
}
@@ -2504,7 +2504,7 @@ impl Compiler {
25042504
sub: &Sp<Subscript>,
25052505
for_what: impl fmt::Display,
25062506
) -> Option<SubNOrSide> {
2507-
match (sub.value.num, sub.value.side) {
2507+
match (&sub.value.num, sub.value.side) {
25082508
(None, None) => {
25092509
self.add_error(sub.span.clone(), "Subscript is incomplete");
25102510
None

src/format.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,7 @@ F ← (
19941994
| 3)
19951995
)
19961996
)
1997+
⊟₁₂₃₄₅₆₇₈₉₀₁
19971998
";
19981999
let formatted = format_str(input, &FormatConfig::default()).unwrap().output;
19992000
if formatted != input {

src/lsp.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -720,18 +720,17 @@ impl Spanner {
720720
}
721721
#[allow(clippy::match_single_binding)]
722722
Word::Subscripted(sub) => {
723-
let n = Some(sub.script.value);
723+
let n = Some(sub.script.value.clone());
724724
match &sub.word.value {
725725
Word::Modified(m) => {
726726
match &m.modifier.value {
727727
Modifier::Primitive(p) => {
728728
spans.push(
729-
m.modifier.span.clone().sp(SpanKind::Primitive(*p, n)),
729+
(m.modifier.span.clone())
730+
.sp(SpanKind::Primitive(*p, n.clone())),
730731
);
731732
spans.push(
732-
sub.script
733-
.span
734-
.clone()
733+
(sub.script.span.clone())
735734
.sp(SpanKind::Subscript(Some(*p), n)),
736735
);
737736
}
@@ -758,7 +757,9 @@ impl Spanner {
758757
spans.extend(self.words_spans(&m.operands));
759758
}
760759
Word::Primitive(p) => {
761-
spans.push((sub.word.span.clone()).sp(SpanKind::Primitive(*p, n)));
760+
spans.push(
761+
(sub.word.span.clone()).sp(SpanKind::Primitive(*p, n.clone())),
762+
);
762763
spans
763764
.push(sub.script.span.clone().sp(SpanKind::Subscript(Some(*p), n)));
764765
}
@@ -1599,7 +1600,7 @@ mod server {
15991600
let mut tokens = Vec::new();
16001601
let mut prev_line = 0;
16011602
let mut prev_char = 0;
1602-
let for_prim = |p: Primitive, sub: Option<Subscript>| {
1603+
let for_prim = |p: Primitive, sub: Option<&Subscript>| {
16031604
let args = p.subscript_sig(sub).map(|sig| sig.args()).or(p.args());
16041605
Some(match p.class() {
16051606
PrimClass::Stack | PrimClass::Debug | PrimClass::Planet
@@ -1625,7 +1626,7 @@ mod server {
16251626
SpanKind::Number => UIUA_NUMBER_STT,
16261627
SpanKind::Comment | SpanKind::OutputComment => SemanticTokenType::COMMENT,
16271628
SpanKind::Primitive(p, sub) => {
1628-
let Some(stt) = for_prim(*p, *sub) else {
1629+
let Some(stt) = for_prim(*p, sub.as_ref()) else {
16291630
continue;
16301631
};
16311632
stt
@@ -1653,7 +1654,7 @@ mod server {
16531654
BindingDocsKind::Error => continue,
16541655
},
16551656
SpanKind::Subscript(Some(prim), n) => {
1656-
let Some(stt) = for_prim(*prim, *n) else {
1657+
let Some(stt) = for_prim(*prim, n.as_ref()) else {
16571658
continue;
16581659
};
16591660
stt

src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,7 @@ const DYADIC: Color = Color::Blue;
12261226
const MONADIC_MOD: Color = Color::Yellow;
12271227
const DYADIC_MOD: Color = Color::Magenta;
12281228

1229-
fn color_prim(prim: Primitive, sub: Option<Subscript>) -> Option<Color> {
1229+
fn color_prim(prim: Primitive, sub: Option<&Subscript>) -> Option<Color> {
12301230
match prim.class() {
12311231
PrimClass::Stack | PrimClass::Debug | PrimClass::Planet
12321232
if prim.modifier_args().is_none() =>
@@ -1281,7 +1281,7 @@ fn color_code(code: &str, compiler: &Compiler) -> String {
12811281
}
12821282
}
12831283
let color = match span.value {
1284-
SpanKind::Primitive(prim, sig) => color_prim(prim, sig),
1284+
SpanKind::Primitive(prim, sig) => color_prim(prim, sig.as_ref()),
12851285
SpanKind::Ident {
12861286
docs: Some(docs), ..
12871287
} => match docs.kind {
@@ -1303,7 +1303,7 @@ fn color_code(code: &str, compiler: &Compiler) -> String {
13031303
g: 136,
13041304
b: 68,
13051305
}),
1306-
SpanKind::Subscript(Some(prim), n) => color_prim(prim, n),
1306+
SpanKind::Subscript(Some(prim), n) => color_prim(prim, n.as_ref()),
13071307
SpanKind::Comment | SpanKind::OutputComment | SpanKind::Strand => {
13081308
Some(Color::BrightBlack)
13091309
}

0 commit comments

Comments
 (0)