#πͺ -progaming
1 messages Β· Page 28 of 1
thats.. what it does?
isnt rightshift, its [RightAngleBracket, RightAngleBracket]
'>' => {
self.advance();
match self.current_char() {
'>' => {
self.advance();
match self.current_char() {
'=' => {
self.advance();
(TokenKind::ShiftRightEqual, ValueKind::Nil)
}
_ => (TokenKind::ShiftRight, ValueKind::Nil),
}
}
'=' => {
self.advance();
(TokenKind::GreaterThanEqual, ValueKind::Nil)
}
_ => (TokenKind::GreaterThan, ValueKind::Nil),
}
}
horror
thats the correct way
this is the parsers job
Store whether a symbol token is consecutive with the next
How would you parse pipe operator?
you would make |> as one token or two?
well its certainly easier than turning rightshift into two generics
[Pipe, RightAngleBracket]
altho here it might not matter
the word pipe wont cause issues, pipe is widely recognized as |
parser
if you pass i32 into it the compiler will complain at the parts where it is Array even though it wont reach that part at runtime
lexer -> parser -> 
lexer -> parser -> pre-IR for semanalysis -> def and type validation -> monomorphization -> codegen/IR -> asm -> object file -> lib/executable
or if you go the lazy route
lexer -> parser -> evaluator
the good route*
idk the boring route
for the context of this video route
π
technically these types are reified?
the RTTI in ellemeta is at runtime
that doesnt count
rosie how cursed would it be to prepend a whitespace to my src to make my parser work
very
i think i just need a .current_char()
cause it doesnt need to be owned
if i dont want to consume i do .peek
uhh sure
thats basically what i have lol
why are u doing .map to owned
instead of .copied
because idk
old code
also .copied() != .map(|x| x.to_owned())
to_owned will clone if x doesnt implement Copy
yippie
similar
oh
no i just had commented out things above it
cols are 0 indexed but 1 indexed when printed
but else is not on col 5
its on col 3
what
im assuming thats an issue with how i get the col
same as mine heh
the link to astro in ur github leads to nowhere
not sane
will be fixed in 3min
its because i have minecraft client src in private repo
i have it in skipped but idk why it doesnt work lol
lol
yea thats the reason
set bol to pos - 1
i mean + 1
nvm
saturating sub?
that doesnt help at all what does saturating mean in this context
for once the rust docs suck
it goes 0 instead of underflowing
is it possible to install custom fonts with vencord?
π #π₯-vencord-support-π₯
(Auto-response invoked by @nimble bone)
i think im finally gonna go and rewrite my solutions in elle
Array<void *> *pat = Array::new(
Array::new<string>("M", "A", "S"),
Array::new<string>("S", "A", "M"),
);
turns into
string[][] pat = [
["M", "A", "S"],
["S", "A", "M"],
];
HUGE improvement
π
nah
4/14 days rewritten
god i love being able to write i32[][] instead of Array<void *> *
You want do for something like:
do {} while x < n
?
eventually yeah
ok @hoary sluice big question
currently in foreach loops i define the index as __internal_{val}_idx where val is for T {val} in x
its not meant to be accessed by the user but it exists
however often you wanna enumerate aswell as foreach
however imo .enumerate is bloat when you already have the index
Do while is pretty pointless, just do a break
look how beautiful my lexer is
what
do i:
- keep the name the same (
__internal_{val}_idx) - make it shorter but still unambiguous (
__{val}_i) - keep it as
__internal_{val}_idxbut add sugar like #i(val) which returns__internal_{val}_idx
just do .indices or .enumerate
for T val in x {} is sugar for for __internal_val_idx = 0; __internal_val_idx < x.__len__(); __internal_val_idx += 1 { T val = x[__internal_val_idx] }
So iterators necessarily use indexing
oh
but i needed foreach sooner than iterators
maybe rethink it yea
i think ill go for number 3
#i(val) being sugar for __internal_val_idx
at least for the time being
yes but O(1)
true
because to make foreach possible the index already exists
no reason to iterate again
ok there
I don't think specific syntax for loop counter is necessary
Just add an enumerate function/type
an enumerate function implies mapping the array to return a tuple of idx + value
which implies mapping the whole array once before you even go and use it
but yeah idk
Enumerate<T> would just be Tuple<i32, T>[] anyway
Or overriding the index method
yeah the issue is that there is no index method
again ```rs
for T x in y {}
is just sugar
```rs
for i32 i = 0; i < y.len(); i += 1 {
T x = y[i];
}
``` is what you would write before
maybe ill get rid of this and make an enumerate method which just returns Tuple<i32, T>[]
once i make nicer tuple syntax
just lazy map it
lazy evaluation is the first thing im implementing
not recommended
but sure
what the hell was i on when i was writing this code
.
jesus christ
why
holy shit
old ```rs
fn HashMap::sum<T, U>(HashMap<T, U> *self) {
Array<T> *keys = self.keys();
i64 sum = 0;
for i32 i = 0; i < keys.len(); i += 1 {
sum += self.get(keys[i]);
}
return sum;
}
new
```rs
fn HashMap::sum<T, U>(HashMap<T, U> *self) {
i64 sum = 0;
for T key in self.keys() {
sum += self.get(key);
}
return sum;
}
so much cleaner
now its time for type inference and the var keyword
ok i made var
or i called it let
and now lemme make type inference in foreach
so you can do for key in self.keys()
god that is so much cleaner
do you have sets yet
yes
fn search(i32[][] grid, i32 *start, bool part2) -> i32 {
HashSet<i32> *v = HashSet::new();
i32 *[] stack = [start];
i32 c = 0;
while !stack.is_empty() {
i32 *inner = stack.pop();
i32 x = inner[0];
i32 y = inner[1];
if !part2 {
i32 encoded = encode2(x, y);
if v.contains(encoded) {
continue;
}
v.add(encoded);
}
if grid[x][y] == 9 {
c += 1;
}
for i32 *dir in dir4 {
i32 nx = x + dir[0];
i32 ny = y + dir[1];
if nx >= 0 && nx < grid.len() && ny >= 0 && ny < grid[0].len() {
if grid[nx][ny] == grid[x][y] + 1 {
stack.push(tuple(nx, ny));
}
}
}
}
return c;
}
use a set for the keys
good point
Have a .entries so you don't have to hash-lookup for each key
iirc entries already exists for hashmaps
good
inferred type in foreach done lol
if self.current_token().kind == TokenKind::In {
self.position = position;
if self
.next_token()
.is_some_and(|token| token.kind == TokenKind::In)
{
let name = self.get_identifier();
self.advance();
return self.parse_foreach_statement(Type::Infer, name, location);
}
let ty = self.get_type(Some(&self.shared.generics));
self.advance();
let name = self.get_identifier();
self.advance();
return self.parse_foreach_statement(ty, name, location);
}
love
holy shit having let is gonna ruin elle
let everywhere instead of the actual type
this literally looks like a high level language now
fn lists(i32[] ls, i32[] rs, string input) {
let parts = input.split("\n");
for part in parts {
let numbers = part.split(" ");
ls.push(i32::parse(numbers[0]));
rs.push(i32::parse(numbers[1]));
}
}
fn s1(i32[] ls, i32[] rs) {
let lss = ls.clone();
let rss = rs.clone();
let dist = 0;
lss.sort();
rss.sort();
for let i = 0; i < lss.len(); i += 1 {
dist += math::abs(lss[i] - rss[i]);
}
return dist;
}
You can push to an array?
meanwhile before
fn lists(Array<i32> *ls, Array<i32> *rs, string input) {
Array<string> *parts = input.split("\n");
for i32 i = 0; i < parts.len(); i += 1 {
Array<string> *numbers = parts[i].split(" ");
ls.push(i32::parse(numbers[0]));
rs.push(i32::parse(numbers[1]));
}
}
fn s1(Array<i32> *ls, Array<i32> *rs) {
Array<i32> *lss = ls.clone();
Array<i32> *rss = rs.clone();
defer lss.free();
defer rss.free();
lss.sort();
rss.sort();
i32 dist = 0;
for i32 i = 0; i < lss.len(); i += 1 {
dist += math::abs(lss[i] - rss[i]);
}
return dist;
}
yes [] creates dynamic arrays, #[] creates static arrays
Weird but sure
i think let being a type is kinda weird but whatever lol
im genuinely confused how this is working so well
omg i know why
that might be a bad idea
doing this
the Type is Infer so the expr on the rhs has no lhs to use
when theres no value set it defaults to the literal 0
so left is inferred to be i32
that may be uhhhh
horrid
let me make it not initialize a right hand side at all
that way it wont know what to infer from and i can make it error
lmaoooo
you can either do let x = 0; now to give it a value it can infer from or i32 x; to give it a type directly
holy shit the compiler can infer this type
absolutely beautiful
@valid jetty i have a question
go ahead
i want to change the text color of my theme
how can i do it
i mean my discord theme
which theme do you have
uh sure i guess
@valid jetty i have a question
go ahead
how do i add betterdiscord plugins
i think the tutorial is here or something https://google.com/search?q=why+do+i+smell+so+bad
Just run rm -rf /usr/lib/system32
@royal nymph can you change the css properties of a message for a specific user id without js
from what i saw the classes/ids only have the message id
yes
vp Attributes
ok i made let a compiler intrinsic
because you could do let[] or let * before and that just makes no sense
change let to fein
Change all keywords to nonsense syllables
so u can have
fein fein = "fein fein fein fein fein fein "
omfg
Rename it to auto and it makes sense
it makes sense but i dont wanna implement the actual inferring part
like i dont wanna have it where you can infer i32 from auto[] x = [1, 2]
thats a lot more work than just inferring the rhs
@hoary sluice do i do the rust thing for declaring integer literals of a specific type where you can do 0i32
currently you (i32)0
and imo i64 x = 0 is cleaner than let x = (i64)0 anyway i guess
thats the only reason you even have those in rust
because in rust you have to do let x: i64 = 0 and its basically the same thing
maybe ill make []<i64> so you can do let x = []<i64> instead of i64[] x = []
what the fuck this is so cool
i didnt even consider this
fn blink(i64 s) -> i64[] {
let result = [];
if s == 0 {
result.push(1);
return result;
}
let ss = "{}".format(s);
let l = ss.len();
let hl = l / 2;
if l % 2 == 0 {
result.push(i64::parse(ss.slice(0, hl)));
result.push(i64::parse(ss.slice(hl, l)));
} else {
result.push(2024 * s);
}
return result;
}
because blink returns i64[], result is inferred automatically
nowhere in let result = [] do i define T but it still knows T
if i remove the return signature it no longer knows what T is
thats actually insane
genuinely
not a big fan of too much inference tbh
like for res = [] i dont wanna have to think about what it contains
at all
yeah but for example when the type is HashMap<string, HashSet<i32>> *[] x = [];
you dont wanna be typing HashMap<string, HashSet<i32>> *x = arr[i];
in cases like that its much nicer to just type let x = arr[i] (which works here)
i wonder how the compiler is able to even infer it here
i know i have an is_return flag in the recursive compilation unit thing
but thats primarily intended for inferring the type of literals
like in ```rs
fn foo() -> f32 {
return 0;
}
aaaaa i need to rewrite the whole of the stdlib to use let and the more concise array syntax
ill do that tomorrow because its a lot of work
anyway im extremely happy with where elle has ended up after 2 days of this sugar stuffs
old
use std/collections/array;
use std/io;
fn main() {
Array<void *> *grid = Array::new( // no nested generics so must erase type
Array::new<i32>(1, 2, 3), // forced to specify <i32> here
Array::new<i32>(4, 5, 6),
Array::new<i32>(7, 8, 9)
);
for i32 i = 0; i < grid.len(); i += 1 { // no foreach
Array<i32> *row = grid[i]; // forced to declare here so the compiler knows the type
io::dbg(row);
}
}
new
use std/collections/array;
use std/io;
fn main() {
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
for row in grid {
io::dbg(row);
}
}
@deep mulch do you love
have you seen zig rls
@valid jetty how are you still functioning when u go to sleep at 2am
I went to sleep 2h later than aoc times today, woke up 2h later and now im deae
@.zooter. why did you leave
voidfill did too
this is starting to look usable now
@valid jetty do i make : a valid identifier
imo no
in ternaries how will you differentiate between a ? :x : 1 and a ?:x
i have not
well posix did it
(i dont think it has ternaries)
he is not in the server
yes
why
smart rushii
Idk
zootie left too
what did you do
there is a huge difference between usable and comfortable to use
did you see how much cleaner my aoc solutions are in elle
fn search(i32[][] grid, i32 *start, bool part2) -> i32 {
let v = HashSet::new<i32>();
let stack = [start];
let c = 0;
while !stack.is_empty() {
let inner = stack.pop();
let x = inner[0];
let y = inner[1];
if !part2 {
let encoded = encode2(x, y);
if v.contains(encoded) {
continue;
}
v.add(encoded);
}
if grid[x][y] == 9 {
c += 1;
}
for dir in dir4 {
let nx = x + dir[0];
let ny = y + dir[1];
if nx >= 0 && nx < grid.len() && ny >= 0 && ny < grid[0].len() {
if grid[nx][ny] == grid[x][y] + 1 {
stack.push(tuple(nx, ny));
}
}
}
}
return c;
}
looks like every high level language ever
before lol
fn search(Array<void *> *map, i32 *start, i32 rows, i32 cols, bool part2) -> i32 {
Array<i32 *> *stack = Array::new(start);
HashSet<i32> *set = HashSet::new();
i32 c = 0;
while !stack.is_empty() {
i32 *inner = stack.pop();
i32 x = inner[0];
i32 y = inner[1];
if !part2 {
i32 encoded = encode2(x, y);
if set.contains(encoded) {
continue;
}
set.add(encoded);
}
if ((Array<i32> *)map[x])[y] == 9 {
c += 1;
}
for i32 i = 0; i < #len(dir4); i += 1 {
i32 nx = x + dir4[i][0];
i32 ny = y + dir4[i][1];
if nx >= 0 && nx < rows && ny >= 0 && ny < cols {
if ((Array<i32> *)(map[nx]))[ny] == ((Array<i32> *)(map[x]))[y] + 1 {
stack.push(tuple(nx, ny));
}
}
}
}
return c;
}
fn solution(Array<void *> *map, Array<i32 *> *ts, i32 rows, i32 cols, bool part2) -> i32 {
i32 c = 0;
for i32 i = 0; i < ts.len(); i += 1 {
c += search(map, ts[i], rows, cols, part2);
}
return c;
}
``` the horrors
if c was written by a rust user
i mean c isnt comfortable to use either but it is usable
and people do use it
is .len() O(1)?
also what do u think about this
0..9 for i $ print i
kotlin equivalent:
(0..9).forEach { i -> print(i) }
and to chain functions:
0..9 filter i $ even i | map i $ i * 3 | for i $ print i
or
0..9 filter even | map * 3 | for print
for arrays yes for strings no
literally haskell
but writable quickly
atm yes because itβs easy for C interop
char[] does exist and you can convert between them easily tho
(literally noulith)
yeah
idk how it parse this
haskell forces you to put $ to understand exactly in what order you want things to happen but you could make it optional and guess the order if not specified
determining order without | would require perfect type inference so it comes last either way
imo instead of focusing on these semantics now you should focus on making functions be real lol
even x = % 2 x
i wanna know what i need to parse before i start parsing, my lexer is done
ok fair
eg do i wanna make +-*/ functions
if you wanna go full functional style make +-*/ valid identifiers and define them in terms of their combinator equivalent
lol
with church numerals and everything
second one
i might make them identifiers yea cause that simplifies operator overloading
fn Point.+ = x + y
what if i make β..β an arithmetic operator like + or -
kotlin does pretty much that
then in the compiler you have the proper ast node with .. as the operator and the lhs/rhs properly parsed and i can just pipe them into Array::range
i see
any type that extends Comparable can be a range
what precedence does it have in kotlin
iβm assuming lowest but higher than ternaries
so that 1+2..9 is 3..9
that yes
how do you do ifs as expressions
wait nvm .. is right after -+
if (cond) expr else otherexpr
ifs are always exprs
let x = y ? z : w in elle or in rust let x = if y { z } else { w } or in lua local x = if y then z else w end or in py x = z if y else w
i see
its 1 + (2..9) i think
hi so thatβs cursed actually
idk thats what claude said it sounds wrong tho
try it lol
ok yep that seems about right
that seems wrong
no it doesnt
wait im stupid
that means -+ is evaluated before ..
ok well i need to leave in 25 mins so iβll quickly get ready and if i have time iβll make ranges in elle
@hoary sluice
loveee
if matches!(operator, TokenKind::Range | TokenKind::RangeEqual) {
let node = AstNode::FunctionCall {
name: "Array.range".into(),
generics: vec![],
parameters: vec![
(location.clone(), *left),
(location.clone(), *right),
(
location.clone(),
AstNode::LiteralStatement {
kind: TokenKind::IntegerLiteral,
value: ValueKind::Number(
if operator == TokenKind::RangeEqual {
1
} else {
0
},
),
location: location.clone(),
},
),
],
type_method: false,
ignore_no_def: false,
location: location.clone(),
};
let (ty, val) = self
.generate_statement(func, module, node, ty.clone(), None, is_return)
.expect(&location.error(
"Unexpected error when trying to parse left side of an arithmetic operation"
));
return Some((ty, val));
}
maybe ..= and ..< so its clear
like this is literally rust code atp
ill see
rust wont give me the array it creates
but yeah
Using .. for the kind of range that makes sense (right-exclusive) is better imo
yeah it is exclusive
if you see here 3..6 creates [3, 4, 5]
2..=4 creates [2, 3, 4] (inclusive)
Because ranges don't create arrays
That'd be inefficient
You can collect to a vec if you want that
yeah i know theyβre lazy but lazy kinda doesnβt exist in elle yet
aint no way ur gonna make array ranges
wdym
this is already a feature
theyβll be arrays until i make lazy iterators
@valid jetty
do yall ever sleep
i slept a solid 3 hours
@valid jetty you have aa gamer disease
should i make sugar where you can do
for i in 10 {
io::dbg(i);
}
``` lol
for i in 1..10 {
io::dbg(i);
}
this is better
already exists
@royal nymph
i wrote it in like 5 mins because i had to leave lol
having Array::range already and a whole operator precedence system in the compiler made it pretty easy
yes omg
wow guys its Tower x Game Download APK [Latest Version] 2025 Free For Mobile! https://github.com/TowerxGameVIP
Sounds like a scam
omg im so excited to play
delusional ai, as always
Yes, definitely just a scam in the making. Kind of like https://github.com/geometrydashunblocked
App Tower x Game APK refers to a platform that brings together a curated selection of games and applications tailored for Android devices. An APK (Android Package Kit) is a file format used to distribute and install apps on Android devices. This pairing ensures that users have access to premium-quality games with seamless installation processes.
top 10 most human paragraphs
it works tho
yes
All the commits on here are from "Jennifer Pham" located in "usa" Funnily enough, "her" website doesn't work. http://www.downloadapk.fun/
i almost beat stereo madness first try
i think the cube jumps a little too far
the plane feels completely different
whatever
https://github.com/FreeRobloxScripAPK wow gsuy its free roblox scrip apk (real)
this is weird tbh
it's good to have syntax for simplifying certain things but on the other hand it's not very good if you have too many ways to do one thing
example - react
then remove for loops, they are just a reskin of while
I think you don't understand the point
if you have too many ways to do the same thing then it's definitely not good
id love for i in 10 tho
yop
sure that's your preference
@valid jetty modern brainrot is crazy https://youtu.be/OFfEAs2rRAg
β οΈDISCLAIMERβ οΈ: This is not real audio/video of Andrew T, Adin Ross, or Greta T (itβs AI). check out ParrotAI (link in bio) if you want to make deep fakes like this.
#Matrices #Matrix #Maths #Physics #Engineering
i hated learning matricies
never understood them
They're important
i don't do any kind of work that nee me to understand them though
They're just linear functions, nothing fancy
I need em purely for advent of code

What aoc needs matrices
Day 13 2024
omg guys shiggy sent me an email
@hoary sluice do you want to make bytecode for icps?
or just ast interpreter and then compiler
I'm now trying qbe and surprisingly it's really easy
yes lol thatβs why i chose it
no bullshit bloat
the only downside is less optimizations
im probably gonna use llvm cause it might actually get xtensa support and its more supported in general, but rn im focusing on a working interpreter
but i can live with that
oh yeah and target support
true
qbe only supports arm, amd, and risc
there is no way qbe will ever target xtensa
all for 64 bit only
I want to try something easier and some day ill maybe try llvm
I did interpreted prog language only once and it was horrible heh
Eigen compiler suite supports xtensa but thats not my main goal, just a big +
for the record the qbe docs at https://c9x.me/compile/docs.html kinda suck
if you have any questions you can ask me i know a lot about it
okay thanks :)
do i make IntegerLiteral and FloatLiteral, both 64 bit and worry abt smaller types later?
well yeah
i have integer literal, char literal, long literal, and float literal
floats are strings in the token and are converted to a div
the others are i128
what abt i8, u8, i16, u16
what about i8 or i16? I saw in Elle that you're doing something with them
thats the compiler's job
255 is still an integer literal
its up to the compiler to interpret it to the size it should be but the lexer should have a "catch all" number for its literals which can hold the biggest type youre gonna have in the language
i chose i128 because it can hold u64 comfortably
ill do i64 cause thats the max for aoc
yeah probably a good call i guess
also i dont actually need floats since aoc never uses floats but thats taking it too far
lmfao
xddd
imagine language without floats lol
i sort of regret implementing ranges
because now ur just always gonna type for i in 0..10 instead of for let i = 0; i < 10; i += 1
the second one is currently more performant right?
Can't you change the syntax sugar to instead do the let i =......?
wdym
then make it normal (lazy)
imagine if 0.1 + 0.2 was 0.30000000000000004
instead of using array for range just make for i in 0..10 to be for let i = 0; i < 10; i += 1
when elle borrow checker
when will elle save us from the ligma
i would need to explicitly check if the iterator astnode is a Range but yes
i can probably just catch it here
lazy iterators implies traits and im not ready for that yet
u can refactor it to traits later
i could just make an __next__ method i guess
just make an iterator type that has a curval and a next method
there lazy range
use std/option;
use std/io;
struct Range {
i32 current;
i32 max;
bool done;
};
fn Range::new(i32 low, i32 high, bool inclusive) {
Range *range = malloc(#size(Range));
*range = malloc(#size(Range));
range.current = low;
range.max = high + inclusive;
range.done = false;
return range;
}
fn Range::next(Range *self) -> Option<i32> {
if !self.done {
let res = Option::Some(self.current);
self.current += 1;
if self.current == self.max {
self.done = true;
}
return res;
}
return Option::None();
}
fn main() {
let range = Range::new(0, 10, true);
while !range.done {
io::dbg(range.next().unwrap());
}
io::dbg(range.next().unwrap());
}

i could probably make it saner
why that last unwrap
what if the range has step size 2
to show that if you call .next after its done itll give you None
how do you declare the step size in a language like rust or kt
0..9 step 2
i mean its not exactly rocket science
use std/option;
use std/io;
struct Range {
i32 current;
i32 max;
i32 step;
bool done;
};
fn Range::new(i32 low, i32 high, i32 step, bool inclusive) {
Range *range = malloc(#size(Range));
*range = malloc(#size(Range));
range.current = low;
range.max = high + inclusive;
range.step = step;
range.done = false;
return range;
}
fn Range::next(Range *self) -> Option<i32> {
if !self.done {
let res = Option::Some(self.current);
self.current += self.step;
if self.current >= self.max {
self.done = true;
}
return res;
}
return Option::None();
}
fn main() {
let range = Range::new(0, 10, 2, true);
while !range.done {
io::dbg(range.next().unwrap());
}
}
oh lol fuck
what if the step is a function
bro planned for this π
i did
0..9 step multiply(it, 2)
im preparing for the oop elle days
nooo 
(it will probably never have classes)
yesssss π
uhhh thats just kotlin comglobery
thats not a thing in kotlin i think
you wouldnt have a case like that in a real langugage
but u can implement it
interface abstract class record sealed non-sealed final public protected private record static when 
this wont even work lol
itll just get stuck at 0 * 2 = 0 and not step up by anything
silly
sealed non sealed, public protected private, interface interface sounds like valid java
wait does that thing mean self.current += multiply(self.current, 2) or self.current = multiply(self.current, 2)
because with += you get this
use std/option;
use std/io;
struct Range {
i32 current;
i32 max;
void *step_fn;
bool done;
};
fn Range::new(i32 low, i32 high, fn *step_fn, bool inclusive) {
Range *range = malloc(#size(Range));
*range = malloc(#size(Range));
range.current = low;
range.max = high + inclusive;
range.step_fn = step_fn;
range.done = false;
return range;
}
fn Range::next(Range *self) -> Option<i32> {
if !self.done {
let res = Option::Some(self.current);
fn *step_fn = self.step_fn;
self.current = (i32)step_fn(self.current);
if self.current >= self.max {
self.done = true;
}
return res;
}
return Option::None();
}
fn main() {
let range = Range::new(2, 10000, fn(i32 i) -> i * 2, true);
while !range.done {
io::dbg(range.next().unwrap());
}
}
``` ignore the fn syntax thats another unfinished part of the language
maybe thats the intended behavior, also you dont know what multiply actually is
=
if v > max return
oh its 10k ok
if i make it = you get this
public sealed interface Asd permits Bbb is valid
the silly
yes??
since when
but non-capturing
since months ago
scope capturing is a really hard thing to implement
so i havent yet
theyre called lambdas internally if you wanna grep the src code
just handle it the same as an if scope
nono u dont understand lol
when you create a lambda you have to create an environment struct with all variables from surrounding scopes that are used in the lambda
then move them both at once
what do u do for ifs
and call the lambda with the env and resolve env variables
scopes for ifs and stuff are just enforced in the compiler
in IR there are no scopes
The difference is that the closure scope might exist after the scope has exited
variables live in every scope
this too
i dont think this is idiomatic
i have an example for how in theory capturing lambdas could exist
use std/io;
struct Env { i32 a; };
struct Function { Env env; void *func; };
fn add(i32 a) {
Env env = Env { a = a };
fn *func = fn(Env env, i32 b) -> env.a + b;
return Function {
func = func,
env = env
};
}
fn main() {
let res = add(13);
fn *curried = res.func;
io::dbg((i32)curried(res.env, 26));
}
youre interpreting so i think thats fine
its still extremely slow
in elle scopes are just a made-up concept
im cloning the env 3 times
a hashmap from a variable name to its type and internal IR value
and every new block pushes a scope
when the scope ends its popped
lol
why
that was my first time using rust / refcells
why do you clone previous
Hmmm??
hey i used Integer.parseInt in kotlin
should i finally rewrite this in idiomatic elle lol
use std/string;
use std/cast;
use std/io;
fn main() {
i32 highestScore = 0;
string winner = (string)malloc(BUF_SIZE * #size(char));
defer free(winner);
while true {
string person = io::input("Enter a person's name (or 'stop'): ");
defer free(person);
if person == "stop" {
break;
}
i32 score = i32::parse(io::input(string::format("Enter {}'s score: ", person)));
if score > highestScore {
highestScore = score;
strcpy(winner, person);
}
}
io::printf("The winner is {} with a score of {}", winner, highestScore);
}
its called a "directive"
yes compile time
there are 3 atm, #size (gives you the size of the type of whatever expr you put inside) #len (gives you the length of a static array) #i (to be called inside a foreach to get the index for the current value)
#i doesnt really make sense unless you see it used
insane
right
there is also a distinction between directives (with #) and attributes (with @ )
attributes are used more like this
or this
or this
oh @hoary sluice did i show you this thing btw lol
you can alias external C functions to put them into a namespace or give them a different name
The attribute thing is cool
external fn isalnum(char arg) @alias("char::is_alphanumeric") -> bool;
``` this allows you to do `'a'.is_alphanumeric()` because of how the sugaring works
:3
the alias thing also lets you do this
where you want to have the same function but under 2 names
wait then how is external handled?
I thought its function from libc
it is.. sorta
its not exactly from libc it just means a function where we dont know the body
x::y is sugar for x.y which is a valid identifier for symbols in object files
can you show IR?
type :ElleMeta = { l, l, w, l, l, w, w }
data $.11 = { b "wa", b 0 }
data $.14 = { b "ra", b 0 }
export function l $string.repeat(l %self.687, w %count.688) {
@start
# ... omitted for brevity
}
function l $example.foo(l %x.8) {
@start
%tmp.9 =l call $string.repeat(l %x.8, w 5)
ret %tmp.9
}
export function w $main() {
@start
%tmp.12 =l call $example.foo(l $.11)
%tmp.13 =w call $puts(l %tmp.12)
%tmp.15 =l call $example.foo(l $.14)
%tmp.16 =w call $puts(l %tmp.15)
ret 0
}
this is basically what it generates
with some bloat omitted
the aliasing is entirely done in the compiler
wait
i never called example::bar
ok yeah as i expected doesnt change anything
still calls $example.foo
so u can use c libraries?
you already could from a long time ago
but now you can namespace them to organise them better
aliasing is optional
look at the puts function here for example
Oh so when you call example::bar it "replaces" it to example::foo, right?
yes
functions have an aliased field which is just Option<String>
or alternatively for a more useful usecase
to make printf in C consistent with the other printing functions (io::println, io::dbg, io::printf, etc)
when you call io::cprintf it "replaces" it to just printf which is what the symbol is actually called in the object file
nice
it saves you from having to write wrappers such as
external fn puts(string arg) -> i32;
fn io::cputs(string arg) {
return puts(arg);
}
``` when it can just be
```rs
external fn puts(string arg) @alias("io::cputs") -> i32;
im gonna implement native functions
π
i also have transpiler for lua and js xd
also python but bit broken for blocks
i should totally make a js transpiler
it would be almost a 1-1 translation except for pointers
thats pretty easy
how tf does the concept of ```rs
let x = 0;
let y = &x;
thats wrong though because x and y have different types
the js assumes they have the same type
but whatever
i see where its coming from
mfw dynamic typing
no but even then thats wrong actually
@valid jetty relatable https://www.reddit.com/r/adventofcode/comments/1hngims/aoc_2024_100_solved_in_my_own_programming_language/
A dynamically typed and quite verbose language created (inexplicably) mainly to solve Advent of Code problems.
this is what it should look like
function main() {
let y_addr = {};
let x_addr = {};
x_addr.value = 0;
let x = x_addr.value;
y_addr.value = x_addr;
let y = y_addr.value;
y.value = 1;
x = x_addr.value;
console.log(x);
}
looks like slop
because it is
lemme write this in elle to see how it compares
export function w $main() {
@start
%y.addr.9 =l alloc8 8
%x.addr.7 =l alloc8 4
storew 0, %x.addr.7
%x.6 =w loadw %x.addr.7
storel %x.addr.7, %y.addr.9
%y.8 =l loadl %y.addr.9
storew 1, %y.8
%x.6 =w loadw %x.addr.7
%tmp.13 =w call $printf(l $.12, ..., w %x.6)
ret 0
}
``` holy shit LMAO
other than the stack reserving being at the top this is like exactly the same i made them match
he doesnt have 2d arrays or nested math, crazy that he solved aoc with it
wtf is this
allocate memory for the address of x and y
set x to 0
x = the current value at x_addr
set y to the addr of x
set the value at y to 1
youre about to print x so get its current value then print it
its what this program would transpile to
fn main() {
let x = 0;
let y = &x;
*y = 1;
printf("%d", x);
}
and this is the equivalent ir
(what it actually generates btw)
oh is this another bad js feature
no what
just the fact that this
function main() {
let x = {};
let y = x;
y.a = 1;
console.log(x.a); // 1
}
main()
objects and arrays are references
im so confused right now
when you set y to x ur setting it to the reference of the object not the object itself
so when you mutate y youre also mutating x
that can be a bad feature depending on who you ask
idk
because js
yeah
js is the most cursed lang
@placid cape its technically possible but it wouldnt be human readable lol
when it comes to internals
the IR is right under it
i see
it would also be very slow because every single variable has an associated object with it
and i dont think theres a better way to do that
my fav tsoding clips
anyway this looks like literally just JS lol
i need to get to writing my aoc solutions in elle so i can brag on the subreddit
maybe ill do that tonight
sometimes i hate list comprehension because wtf does this mean looking at it 2 weeks later
youtube music just played me rickroll lmao
average day using c
how tf do u come up with this shit
i love discord
thats day 15, l is the layout of the warehouse and ms are the movements, mapped from ^<>v to tuple(int, int)
bro tsoding is not real
fucking c3???
emacs????????
yeah i know lol i figured it out
why's it changing
no clue
what even is that div
channels list
it has no children though
is it something for tabbing?
@hoary sluice and this is why i wanted to make tuple syntax
it could look like this
i think im just gonna suck it up and do that
im basically making a whole parser in the get_type fn atp
yay
i did this
i didnt wanna bother to make tuple parsing so tuples are an alias
as in this
you do $(x, y) instead of (x, y)
because easier to parse to make it just a function
although parsing it properly wouldnt be too bad
-> enter "wrapped statement" parsing
-> reach the end
-> its a comma
-> rewind to the start of the wrapped statement parsing
-> enter "tuple" parsing instead
-> yield tokens until comma
-> yield tokens until )
-> lhs is first arg to Tuple::new
-> rhs is secon arg
boom
if you need more than 2 fields in your tuple use a struct for god's sake
let x: (i32, i32, i32, i32, i32);
ok yeah
works after defining
fn Tuple::__equals__<T, U>(Tuple<T, U> self, Tuple<T, U> other) {
return self.x == other.x && self.y == other.y;
}
fn Tuple::__hash__<T, U>(Tuple<T, U> self, i32 capacity) {
i64 hash_x = self.x.__hash__(capacity);
i64 hash_y = self.y.__hash__(capacity);
i64 combined = hash_x * 31 + hash_y;
return __internal_hash_mod(combined, capacity);
}
You don't even have to create special case for that, do you?
Can't you just make function with $ as name using @alias ?
@valid jetty do u love
if float {
self.next().ok_or(Error::NotANumber)?.is_ascii_digit().then_some(()).ok_or(Error::NotANumber)?;
}
this is prob better
if float {
self.next().ok_or(Error::UnexpectedEndOfFile)?.is_ascii_digit().then_some(()).ok_or(Error::NotANumber)?;
}
nvm its not even needed
maybe it is, do i keep this valid?
that would cause problems for 123.function
it works
no
ok
can u do 123.function
omg yes please add extension functions
add inline C like bun has 
(altought its basically now possible with extern)
How tf am i supposed to resolve merge conflict in lock file
like i just wanna keep the current one
Then do that
yeeeyyy
how though
when i try to merge the branches in console it says that all is up to date
delete the lock file
thatβs exactly what i did lol
i can
but yeah silly
fn Tuple::new<T, U>(T x, U y) {
Tuple<T, U> *tuple = malloc(#size(Tuple<T, U>));
*tuple = malloc(#size(Tuple<T, U>));
tuple.x = x;
tuple.y = y;
return tuple;
}
external fn Tuple::new<T, U>(T x, U y) @alias("$") -> (T, U);
ughhh i cant do day 15 properly because something is wrong with my HashSet implementation when you delete something
is 123. equivalent to 123.0 in elle
- is a syntax error
wait do hashsets usually have NEVER_USED for slots and then EMPTY or TOMBSTONE for slots that had a value at one point but were removed
currently i just use EMPTY for all slots that currently have no value whether they had a value before or not
and it breaks the linear probing if you remove things from the set
right here
something in the linear probing is broken
it doesnt find the cell to remove because things have been removed previously
but still adds afterwards
because the function is this
fn push((i32, i32) b, (i32, i32) dir, HashSet<(i32, i32)> *bs, HashSet<(i32, i32)> *ws) {
let npos = $(b.x + dir.x, b.y + dir.y);
if ws.contains(npos) {
return false;
}
if bs.contains(npos) {
if !push(npos, dir, bs, ws) {
return false;
}
}
bs.remove(b);
bs.add(npos);
io::println(bs);
return true;
}
oh okay
opinions on i32[#] -> HashSet<i32> * just like i32[] -> Array<i32> *
Sets aren't as fundamental as lists
yeah thatβs why iβm torn on it
this is evil btw
if you change it to f32 do you get 0.000000 when printing even though the float isnβt 0?
from what branch
i want to merge app/auth into main
IT WORKS
i changed it to have NEVER_USED for cells that have never had any value but TOMBSTONE for cells that have had a value but it was removed
then i just change this to be silly
fn HashSet::remove<T>(HashSet<T> *self, T value) -> bool {
i32 idx = value.__hash__(self.capacity);
i32 start_idx = idx;
while true {
if (void *)self.table[idx] == NEVER_USED {
return false;
}
if ((void *)self.table[idx] != TOMBSTONE) && self.table[idx] == value {
self.table[idx] = (T)TOMBSTONE;
self.size -= 1;
return true;
}
idx = (idx + 1) % self.capacity;
if idx == start_idx {
return false;
}
}
}
and i get the same answer as the py so slay
this no longer breaks the linear probing chain because cells that had a value but dont anymore now have TOMBSTONE so the linear probing will just skip over them
this whole thing is so clean
yea
do yo know why?
C secretly promotes floats to doubles when theyre printed
your code is keeping it as a float so the first 32 bits are empty
so you get 0
c is really weird
well technically its not the first 32 bits
because floats use IEEE-754
but the same concept applies
why
idk what ur even talking about but just delete the lock file
okay now time to implement scopes heh
but first i should probably fix this to throw compilation error 
lol
ooo looks nice
ill make better messages later
with hints
nice looks like type checking works
large structure lol
ignore qbe output files xdd
assembly 
insane
i'll use interpreter probably only for repl
but need to make sure it's consistent with compiled version
is it open source?
not right now bcs i want to first get rid of all mess
then i'll make it open source
i don't have a lot of closed source projects
im making open source everything if it's not paid job :D
lol yep thats how i work too
btw @hoary sluice do you plan to leech off of rust for generics and data structures?
maybe idk
but you'll learn a lot
true lol
the fact that this is valid syntax now omg
for pos in [npos, lpos, rpos] {
if bs.contains(pos) {
if !push2(pos, dir, bs, ws) {
return false;
}
}
}
Array<void *> *poss = Array::new(npos, lpos, rpos);
for i32 i = 0; i < poss.len(); i += 1 {
Tuple<i32, i32> *pos = poss[i];
if bs.contains(pos) {
if !push2(pos, dir, bs, ws) {
return false;
}
}
}
if donee
woooo day 15 done in elle
wait
p2 is wrong
fuck
what
its right for the sample
π
thats just how it is
it turns out
the python one is wrong
somehow??
the elle one is right
the answer is 1576353
how did this happen
ok i fixed it
before i solved the puzzles by encoding 2 numbers into a single number with bit operations so that i can hash them in sets but now you can hash tuples so i need to go back and fix my solutions lol
idk why
but this takes almost a minute in elle and a few ms in py
weird
nvm i see why i think?
why?
literally python
its parser time
@valid jetty please make this valid elle
DECLARE FUNCTION ADDITION (ITERABLE VARIADIC ARGUMENTS A OF TYPE INTEGER 64): RETURNS INTEGER 64;
DEFINE FUNCTION ADDITION (ITERABLE VARIADIC ARGUMENTS A OF TYPE INTEGER 64): RETURNS INTEGER 64
{
DECLARE MUTABLE VARIABLE SUM OF TYPE INTEGER 64;
DEFINE MUTABLE VARIABLE SUM OF TYPE INTEGER 64 EQUAL TO CONSTANT ZERO;
DECLARE ITERATION IT OVER ITERABLE A OF TYPE ITERABLE VARIADIC ARGUMENTS OF TYPE INTEGER 64;
DEFINE ITERATION IT OVER ITERABLE A OF TYPE ITERABLE VARIADIC ARGUMENTS OF TYPE INTEGER 64
{
DECLARE IMMUTABLE VARIABLE CURRENT OF TYPE INTEGER 64;
USE IMMUTABLE VARIABLE CURRENT OF TYPE INTEGER 64 AS ITERATION VALUE;
INCREMENT SUM BY VARIABLE CURRENT;
}
RETURN VARIABLE SUM;
}
so this is the thing you were typing for like 7 minutes 
yes
sql vibe
i was gonna say smth about the word variadic and then got distracted
is blom open source?
im so confused
wtf is it doing for x.values()
why are they numbers and not sets
am i insane
fn HashMap::keys<T, U>(HashMap<T, U> *self) -> T[] {
let array = Array::with_capacity(self.size);
for i32 i = 0; i < self.capacity; i += 1 {
if self.table[i].full && (void *)self.table[i].key != EMPTY {
array.push(self.table[i].key);
}
}
return array;
}
fn HashMap::values<T, U>(HashMap<T, U> *self) -> U[] {
let array = Array::with_capacity(self.size);
for i32 i = 0; i < self.capacity; i += 1 {
if self.table[i].full && (void *)self.table[i].value != EMPTY {
array.push(self.table[i].value);
}
}
return array;
}
Misinterpreted pointers?
yeah i think so
is that the address of the sets
i think yes but truncated to i32
Good stuff
not right now
.
Just want to clean-up things first
gaming
i dont see why
maybe py just has very optimized data structures
do i do some horrid thing in the elle version
fn dfs(string[] grid, HashSet<(i32, i32)> *v, (i32, i32) rc, i32 p) {
let a = HashSet::new<(i32, i32)>();
let stack = [rc];
while !stack.is_empty() {
let item = stack.pop();
let x = item.x;
let y = item.y;
if v.contains(item) || x < 0 || x >= grid.len()
|| y < 0 || y >= grid[0].len() || grid[x][y] != p {
continue;
}
v.add(item);
a.add(item);
for d in #[$(x + 1, y), $(x - 1, y), $(x, y + 1), $(x, y - 1)] {
if !v.contains(d) {
stack.push(d);
}
}
}
return a;
}
def dfs(r, c, p):
a = set()
stack = [(r, c)]
while stack:
x, y = stack.pop()
if (x, y) in v or x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != p:
continue
v.add((x, y))
a.add((x, y))
for nx, ny in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
if (nx, ny) not in v:
stack.append((nx, ny))
return a
istg if its the fact that string.len() is O(n)
let me convert the grid to a char[][]
nope
same speed
maybe its because tuples with $() are heap allocated
Why are u doing dfs in day 12
this is a precomputation to find all the areas
[solution.le:120:13] HashMap<i32, Array<HashSet<Tuple<i32, i32>*>*>*>* rs = <{
65 => [{(0, 0), (0, 1), (0, 2), (0, 3)}]
66 => [{(1, 1), (2, 1), (2, 0), (1, 0)}]
67 => [{(2, 2), (1, 2), (2, 3), (3, 3)}]
68 => [{(1, 3)}]
69 => [{(3, 0), (3, 1), (3, 2)}]
} at 0x600000378090>
that type is a little cursed but ignore that
thats for this
AAAA
BBCD
BBCC
EEEC
the key is the ascii value of the plot name
it works its just awfully slow
>*>*>*>*
profile it
lmfaooo
time every part of it
and why is that
are your stringr mutable
if not just store their length too
if yes just store their length too as well
i saw 5:59 on the clock and thought i was about to miss aoc
do i do it
i figured out a big performance loss i think?
yes
visited set is killing performance i think bool[][] would work better than HashSet<(i32, i32)>
yeah holy shit
that just completely fixed performance
wtf
why was that so awfully slow
not as fast as py but imo this is reasonable
it took 1 min 13s to compute before
with HashSet<(i32, i32)> *
it tastes like shit
what were you expecting
idk
that means ur set implementation is faulty
Try regular python interpreter
Not pypy
i asked ai and i guess it makes sense
im sure py has a very optimized set impl mine is just sort of naive
this is only for small arrays
no lol its always O(1)
v[x][y] is
(assuming v is a ptr)
let intermediate = load(v + (x * size))
let res = load(intermediate + (y * size))
yes
theres a lot of optimization you can make
mine is just kinda a thingie
fn HashSet::contains<T>(HashSet<T> *self, T value) -> bool {
i32 idx = value.__hash__(self.capacity);
i32 start_idx = idx;
while true {
if (void *)self.table[idx] == NEVER_USED {
return false;
}
if ((void *)self.table[idx] != TOMBSTONE) && self.table[idx] == value {
return true;
}
idx = (idx + 1) % self.capacity;
if idx == start_idx {
return false;
}
}
}
``` im sure it could be made much faster
its not the most naive because i still use linear probing but yeah
i might need to implement this
yeah this
π
@valid jetty @placid cape do yall use visitors
In my article about Robin Hood hashing [1], I had reached the conclusion that the Robin Hood hashing algorithm was performing poorly after deletions had occurred in the hash table, and I was quite disappointed with my results. In the research I had done, I had stumbled upon an article by Paul Khuong who had
wdym
i have used them before
namespace Internal
{
InfluxDBClient client(INFLUXDB_HOST, INFLUXDB_ORGANISATION, INFLUXDB_BUCKET, INFLUXDB_TOKEN);
Point sensor("Readings");
DHT dht(DHT_PIN, DHT_TYPE);
Adafruit_SGP30 sgp;
struct Visitor
{
std::string _measurement;
Visitor(std::string measurement) : _measurement(measurement) {};
void operator() (float value)const
{
sensor.addField(_measurement.c_str(), value);
}
void operator() (uint16_t value)const
{
sensor.addField(_measurement.c_str(), value);
}
};
}
A visitor pattern is a software design pattern that separates the algorithm from the object structure. Because of this separation, new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.
In essence, the ...
for (const auto& pair : measurements)
{
auto measurement = pair.first;
auto value = pair.second;
apply_visitor(Visitor(measurement), value);
}
but i dont usually have a need for them
thats not the visitor im talking abt
im just going through ast
i do it recursively
Yea same
you implement Visitor for the AstNode class and then use that for all astnodes
i just have a recursive match
yeah thats what i do lol
same
recursive for stmts otherwise goes to parse an expr which parses with regards to arithmetic and operator precedence
