#๐ช -progaming
1 messages ยท Page 29 of 1
(which is also recursive)
And then for each node type you'll implement it
yes
ive seen that approach used before but i dont personally like it
well I don't have that "interface" but for each node I have different file with function that is called in the match
@hoary sluice is x = (x + 1) % y the same as x = (x + 1) & (y - 1)
ur combining statements and expressions into 1 enum, that seems hard to maintain
because I don't want to end up with 3k lines in one file :3 rosiee
for all y = 2^z
yes, and then in the compiler exprs return Some((ty, val)) and stmts return None
that seems ugly
its a lot more reasonable than it looks
im gonna make everything an expression
yeaaa
how do you determine the return value of while true {}
loops are functions
its an interpreter, im gonna make while a builtin function that just uses rust while in the background
u can return from it
I wonder how to transpile something like
i32 a = if 4 == 7 { return 7; } else { return 9; }
into qbe
i32 a = 9;
I'm not gonna resolve if statements at compile time
at least not now
it's easy to do in interpreter
this is what elle does
hmm
okay
but first I'll have to implement blocks
btw Elle helps me a lot with qbe so thank you so much :D
if you dont create with addrs itll be like
type :ElleMeta = { l, l, w, l, l, w, w }
export function w $main() {
@start
%tmp.7 =w ceqw 4, 7
jnz %tmp.7, @ift.6, @iff.6
@ift.6
%ternary.6 =w copy 7
jmp @end.6
@iff.6
%ternary.6 =w copy 9
jmp @end.6
@end.6
%a =w copy %ternary.6
ret 0
}
:3
I'm using it for compiling when I'm not sure how it should be
@hoary sluice opinions on a std/prelude.le module which just imports all of the common things like io, math, array, tuple, split, char types, etc
since it uses namespaces then it's probably fine
with a submit function ๐
betaveros has his in prelude
should hashset and hashmap be part of it
just import on demand without requiring keywords
what like you see HashMap::new() and you go and import std/collections/hashmap?
instead std/prelude make LSP that'll automatically import things 
idk maybe that could work
or make an lsp already
but thats a lot more complicated idk
pretty sure lsps arent actually that hard
I've never done LSP for language (only zed discord presence) but I think that it's not that hard
I recommend tower lsp crate for rust
they are lol
do i put vectors into the prelude
theres vector2 and vector3 structs with some like things
You should have two variants, with doubles and floats
idk i have them only with floats
double precision is usually not needed when working with vectors
my kotlin aoc points are i32, worst decision of my life
idk I only know that Minecraft uses vectors with doubles
then make them i64 โจ
is it possible to somehow make i128 in kotlin?
this delta couldve been 10s
that would require hours or days of refactoring
BigInteger
what
what
there are hundreds of solutions that use Point, entire grid system (2d, 3d, hex, arbitrary d), line, direction all need to be rewritten to long
i have longpoint but it has no support
oh
just change Int to Long and follow the compilation errors from kt
unless it auto truncates and doesnt tell you
there will literally be thousands and i cba
lmao i guess
upload your project to chatgpt and tell it to do it ๐
so true!!!!
im thinking of converting ```rs
fn main(i32 argc, string *argv) {
io::dbg(argv[1]);
}
```rs
fn _main(string[] args) {
io::dbg(args[1]);
}
fn main(i32 argc, string *argv) {
string[] args = Array::with_capacity(argc);
for let i = 0; i < argc; i += 1 {
args.push(argv[i]);
}
return _main(args);
}
like internally
and all you write as the developer is
fn main(string[] args) {
io::dbg(args[1]);
}
that's good ig
can you write for loop without initialization?
just for i < argc; i += 1
no lol
why not
that sounds dumb
for more complex code, that could leave one wondering where i is defined
or, in other cases, it might cause them to not see that i was actually defined as a variable earlier
this is better written as a range loop with a custom step
for loops can have any code, its just convention to have init, cond, step but you could make it like
for let foo = get(); foo != nil; foo = get_next() {}
and that too yeah
for i in 0..argc
sure just asking bcs its possible in other langs
like for (;i<3;i++)
sorry this is evil actually
oh yeah no you can do that here too
you just cant omit it and expect i to still be defined
ohh
so you can do for ;foo!=nil;foo = get_next(); {}
even something as insane as for for ;; {} ;; {}
guh
but not specifically that because itll break on the first ;
eh?
itll see for for ; and notice that its invalid syntax
so the initializer tokens will be [for] not [for, semicolon, semicolon, curly, curly]
yes
this is valid code lol
xd
me when you could've done i -= i != 0
yeah that works but thats also evil
have i shown you guys the approaching operator
i cant do it in elle but 1 sec
ok well im finally done refactoring all 15 of my solutions in elle to use actual tuples instead of the encoding into single numbers stuff lol
time to start day 16
how am i gonna do day 23 in elle
bron kerbosch
why?
this is with pivoting
can you use cartesian product instead of combinations there
well it would include duplicates, e. g. (a, b, c) and also (c, b, a)
so if you sort it and add to set then you can
yeah ok
oh god defaultdict
oh god heappush heappop
how am i gonna implement these nyaboom~7
oh well i think i know how
i dont really have to implement heappush i can just push normally but i can just write a specialized heappop for this heap specifically
LMAOOO
im so glad i implemented let
you can just sort 
yeah but i didnt implement Ord overloading yet
so itll sort by the pointer lol
i can just find the min value and remove that index
ugh
HashMap.0.2.Triple.0.11.11.11.1.11.1
translates to
Hashmap( 2.Triple(11, 11, 11), 11 )
where 11 is int and 2.x is x*
but its not catching the parts after the first nested struct
wtf is this signature
i should just make a struct atp
KOTLIN
u should make vararg generic
omg thats so smart
that would be so hard ๐ญ
i thought i would need to do that when i first made tuples
do i allow you to do (i32, i32) -> Tuple<i32, i32> * and (i32, i32, i32) -> Triple<i32, i32, i32> *
i can do that its not that hard
just count the number of commas
im gonna make a HashMap.get_or_insert(k, v)
so you can do dist.get_or_insert($$(y, x, ndir), i32::max())
how do you differentiate between returning from the function and returning from the if statement
btw optimization goes as far as -O3 why are you doing O2 lol
is there a specific reason
well its extremely ugly and broken and doesnt work at all soooo
i need to fix it
WHAT
looool
found it
export function l $HashMap.with_capacity.0.2.Triple.0.11.11.11.1.2.Array.0.2.Triple.0.11.11.11.1.1.1(w %initial_capacity.6152) {
how tf do i solve this
why it has identifier length limit lol
you can fork it and remove the limit maybe
true
i mean its there
i can get rid of it
that identifier isnt even that long
oh i see why
in the IR identifiers are statically sized 80 byte long arrays
i wonder if it would all explode if i just increase it to like 240
or like 320
i dont think its a good idea to just remove the check because all that would do is buffer overflow
yeah you need to increase the size
i dont think they'll accept it
im scared if i do theyll be like "the ident name should not be longer than 64 chars if it is youre doing something wrong"
but you can try
yeah
who wants to waste time with compressing names lol
i mean you could probably replace all names to integers but who wants to do it lol
void *[] it is
i mean thats not too hard to do
the problem is even if i do
20.with_capacity.0.2.21.0.11.11.11.1.2.22.0.2.21.0.11.11.11.1.1.1
its still very long
you would have to compress it into one number
how would you go about decompressing that SachiScared
so you need some global counter
oh
i have global counter for data things
so i dont even need the function name here
but i just added it for easier debugging
same with temp variables, i dont need anything else than number
that might be doable but it would ruin the philosophy of my monomorphism approach
you need .
you cant have %1 like in llvm the best you have is %.1
wtf is it
20 => HashMap
21 => Triple
22 => Array
11 => i32
2.x => pointer of x
0 => start of generic scope
1 => end of generic scope
this is what the compiler actually generates
woo
Gj
words 10 tho
hm not bad
lol that was such a good seed
i wonder if i could get 200 on it on qwerty
i started that at 84 wtf
here's mine
if dist.get_or_insert(prev, i32::max()) + (prev.z != current.z ? 1000 : 1) == dist.get_or_insert(current, i32::max()) {
}
``` horror
this is my time 15
and this is typing dbg 10 times
there is NO WAY that just worked first try
better like this
this shouldnt just work
let ecost = i32::max();
let estates = Array::new<Triple<i32, i32, i32> *>();
let tiles = HashSet::new<(i32, i32)>();
for i32 dir in 0..DIRS.len() {
let tmp = $$(end.x, end.y, dir);
if dist.get_or_insert(tmp, i32::max()) < ecost {
ecost = dist[tmp];
estates = [tmp];
} else { if dist.get_or_insert(tmp, i32::max()) == ecost {
estates.push(tmp);
}}
}
while !estates.is_empty() {
let current = estates.pop();
let y = current.x;
let x = current.y;
tiles.add($(y, x));
for Triple<i32, i32, i32> *prev in pre[current] {
let cost = prev.z != current.z ? 1000 : 1;
if dist.get_or_insert(prev, i32::max()) + cost == dist.get_or_insert(current, i32::max()) {
estates.push(prev);
}
}
}
return tiles.size();
```` i refuse
lmfaooo
why is it getting so much more inconsitent
ever since i got long nails i havent been able to type faster than 140 ๐ญ
i could have 160 time 15 if i cut them
@valid jetty isnt lazy evaluation super easy to implement
instead of storing a value u store a value and a list of functions
that sounds like its gonna take 5 mins to implement and then have an edge case that requires redesigning
why a list of functions
i already did lazy evaluation in 5 mins remember
or well specifically 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());
}
in rust this would be like
fn main() {
let range = Range::new(0, 10, true);
while let Some(next) = range.next() {
dbg!(next);
}
dbg!(range.next().unwrap());
}
``` but i dont have that semantic
or wait you said lazy evaluation
not lazy iteration
you could make lazy evaluation pretty easily by just making literally everything a function then when you wanna consume a value you call the function
this is a lot smaller than i thought it would be
I genuinely want to see how much do yall sleep
Every time i look here yall are online
@hoary sluice do i allow for partial generic knowledge like this
where you can have a Foo<T, U> and declare a function like
fn foo<T>(Foo<i32, T> x) {}
loops done ๐ฅ
this is nice
is for sugar for while
there are so many edge cases for generics unfortunately
tomorrow i'll move a lot of things into analyzer
like adding default return type to functions, find missing types (e. g. when you're redeclaring variable), type checking
and then i can remove a lot of things from compiler and interpreter
@valid jetty ragebait https://youtu.be/oUJF7p7vzgQ
main channel - @FaceDevStuff
Patreon: https://www.patreon.com/c/FaceDevStuff
Discord: https://discord.com/invite/W98yWga6YK
Twitter: https://twitter.com/facedevstuff
๐ต The music I use: https://share.epidemicsound.com/vue6wt
Outro song - https://www.youtube.com/watch?v=bIr6E1oTzuM
edited by Linker: https://twitter.com/linker_sh
making a pure functional language is really hard
because io inherently cant be pure functional
so the goal is to be similar to noulith
maybe a little more on the functional side
allow sane io and variables
scala does it well
scala has a lazy keyword but its not default
7h30m a day
thats good
that is so cool but idk if itll be useful
its probably supported everywhere
i shifted my sleep 2h later and now i cant wake up
i need aoc in my life
xddd
ahh i forgot to solve day 8 2015
nvm i'll do it tomorrow
and for 2019 ill implement intcode in blom ๐
maybe ill get done with parser tomorrow
nicee
how are you guys working so fast
it took me 8 months to get elle to a decent state where i could actually use it for most programs
my current js transpiler transpiles:
i32 a = if 5 == 3 {
return 7 + 5;
} else {
return 8 + 5;
}
into something like
let a = (function() {
if (5 == 3) {
return 7 + 5;
} else {
return 8 + 5
}
})();
not very efficient but who cares about js
im sure it'll take us also a long time
i started icps almost a year ago and its barely possible to use (i only worked on at for a month tho)
i had one prog language called frog which was basically monkey lang
if you know what monkey lang is
go tutorial?
why go for blom
i dont know tbh
i really miss
pub enum Asd {
Something(i32),
String(String),
Int(i64)
}
enum with values is amazing feature
gn
absolutely
i wish i used a tutorial for elle lol
wouldve helped
good night tho guys
im gonna keep writing my solutions
day 17 wasnt actually that bad
i can actually just do this to parse lol
fn parse(string contents) {
let lines = contents.split("\n");
let a = lines[0].nums()[0];
let b = lines[1].nums()[0];
let c = lines[2].nums()[0];
let instructions = lines[4].nums();
return Program {
a = a, b = b, c = c,
instructions = instructions
};
}
```i love
fn Array::slice<T>(T[] self, i32 _start, i32 _end) -> T[] {
let start = _start;
let end = _end;
start = start < 0 ? self.len() - start : start;
start = start < 0 ? 0 : start;
start = start >= self.len() ? self.len() : start;
end = end == -1 ? self.len() : end;
end = end < 0 ? self.len() - end : end;
end = end >= self.len() ? self.len() : end;
end = end < start ? start : end;
T[] result = Array::with_capacity(end - start);
for i32 i = start; i < end; i += 1 {
result.push(self[i]);
}
return result;
}
``` i think this is possibly the most cursed slice implementation ive ever written
@hoary sluice ```rs
fn lists(string input) {
let parts = input.split("\n").map(string::nums);
let ls = parts.map(fn(i64[] nums) -> nums[0]);
let rs = parts.map(fn(i64[] nums) -> nums[1]);
return $(ls, rs);
}
it would be pretty easy to make it not
can make it this
fn Array::slice<T>(T[] self, i32 start, i32 end) -> T[] {
let temp = Array::with_capacity(math::next_power_of_2(end - start));
temp.elements = self.elements + (start * #size(T));
temp.size = end - start;
temp.capacity = self.capacity;
return temp;
}
LMAO
Which free scientific computing language is the fastest to program and execute? The answer probably won't surprise you because it's obvious.
Fortran supremacy
MATLAB but gnu edition
does anyone know if ghostty can have transparent backgrounds
An open source matlab copy
probably and if not just set transparency in compositor config 
ngl I should give ghostty a shot when I get home
zed ๐ฅ๐ฅ
I want Zed to be acquired by JetBrains
why lol
Because they will make it usable
they have fleet
Fleet is mid
agreed
Only thing that makes Zed good is that it's fast
Literally it
So if I could have the other JetBrains tools be faster I would be happy

Shrimple as
they would javaify it /s
performance down though
Java doesn't mean low perf tbh
java is pretty performant, but the initial load times are bad
Really depends
which to rust people means a lot
yea its awesome
rust people will find every millisecond for a reason to switch to rust
(im a rust hater)
oxidize yall
Now Zig
havent tried zig
I am a real Zigger
C is the best
"We will take away your need to manage memory and give you borrow checking which you need to worry about the same as memory management!"
hate yourself out of my way
C and Zig let me to the same thing, not to mention the Zig tooling let's you use both in the same project
Like seamlessly
it looks nicer on macos cause it har the stupid title bar on linux and its like 3x biggar and u still cant remove it
havent tried zig tbh
Zed is no good till it has IntelliJ tier plugin integration
I do Java mostly
wth
But Zig has been a treat
i do C mostly for osdev, i might try zig though
id rather see ^^^^^^^^^^^^^^^^^ mutable borrow occurs here than segmentation fault (core dumped) and then have to start it in gdb and decipher the backtrace
im pretty sure gcc has flags to detect possible segfaults
i still use c++ sometimes but only for codeforces
yea ik it is, part of my diploma thesis is written in qt and i absolutely hate it, but its acceptable for competitive programming
i dont like c at all
its still nowhere close to rust error handling, rust tells you exactly what the problem as every time without fail
I'm hoping my teachers will let me make my own OS as a hs diploma
or whatever is that called
i really dont want to make a fucking nextjs site
i was gonna make a compiler but a diploma thesis requires a teammate for an A, otherwise its an F in teamwork and a B an total, and nobody in my class wanted to make a compiler, so now were making a voice assistant in kotlin
with a qt frontend
cause i wanted to try it
and i dont believe in kmp
kotlin should stay on the jvm
leave the native stuff to the fast languages
wait and your qt app was multiplatform?
no
well, you dont have to make multipaltform only apps with kmp
are you sure the desktop version compiles to native?
edited 
also qt might support xtensa/esp32
what
im not using kmp
well qt was the frontend, right?
yes
and the QT app was a dekstop app right
qt widgets (c++)
yes
might work for mobile but i only need it for a raspberry pi and potentially for esp32
I'm also making voice assistant but for one competition
But with hardware
So it's not only application
thats my partners job
What are you gonna use?
weve got the pcb ready (just some switches and leds lol) and hes making a case in fusion360 rn
im gonna give up on recording audio with qt
Cool
just gonna make a python script do it and pipe the output to qt
What if the operator is overloaded and has side effects
not implemented
then i'll reconsider it
currently working on analyzing types
just dont allow side effects ๐
imagine overloading binary operators to send request to AI lmao
why is ur l so weird
ik
but that font has both normal l and the silly one
at least their example used both
@placid cape whats the blom ast of (3 + 3)
also do i merge function and variable ast nodes
and just make
let x = 3
sugar for
fn x
x = 3
ty
i think this is all i need
hm should i make else be an explicit ast node, be part of the if node or just parse an else as if !original_condition
ig option 3 would get difficult to maintain for else if chains
yea i ended up doing that
If {
condition: Box<Expression>,
expression: Box<Expression>,
otherwise: Option<Box<Expression>>,
},
time to define grammar 
enjoy heh
i think im gonna do that for now at least
maker parsing much easier and i might wanna stick with it
This is the only way that makes sense after all
yeah
this is the wip grammar
expression = function | definition | primary ;
function = "fn" IDENTIFIER { TYPE } ;
definition = IDENTIFIER { PATTERN } = expression ;
primary = "true" | "false" | "null" | "(" expression ")" | NUMBER | STRING | IDENTIFIER ;
Is this some specific file format or you just made it
so this is a function
fn add int int int
add x y = x + y
and this is a variable
fn x int
x = 3
In computer science, extended BackusโNaur form (EBNF) is a family of metasyntax notations, any of which can be used to express a context-free grammar. EBNF is used to make a formal description of a formal language such as a computer programming language. They are extensions of the basic BackusโNaur form (BNF) metastasis notation.
The earliest E...
oh okay
In computer science, a parsing expression grammar (PEG) is a type of analytic formal grammar, i.e. it describes a formal language in terms of a set of rules for recognizing strings in the language. The formalism was introduced by Bryan Ford in 2004 and is closely related to the family of top-down parsing languages introduced in the early 1970s.
...
im tryna figure out rn what it means for a function declaration to be an expression
ig u can assing a function declaration to another function
yea
fn a int int
a x = x + fn b int b = 7
@placid cape
this is pointless tho
but itd be valid as a side effect
can you show me more readable pseudo code please xd
I'm not sure if I know what's exactly going on
is it something like
fn a int int
a x = x + fn b int b = 7
equivalent to
fn a int int
a x = x + 7
or
def a(x: int):
return x + 7
just that ur gonna be able to use function declarations as expressions in order for everything to be an expression
And a before the next statement means that's it's in the function body
yes, they are not differentiated
to allow currying
u mean line 2?
its like a switch case
fn a int int
a 0 = 1
a n = n * a n - 1
this is factorial i think
ohhhh
it uses the first one that the argument matches
interesting
its all stolen from haskell
And how do you know which identifier is what
like here you have one argument of type int
but how do you know which identifier is it
in the same order
okay good luck with that
I would probably create some analyzer or something that can match the identifiers to arguments and then it'll be easier to do interpreter/compiler
fn b string int point
b s i = point(0, i) + toint s
fn a int string int point
a x = b (tostring x) 0
a x s i = point(x, i) + toint s
now u can call a either with 1 argument and or with 3 arguments
a "13" returns point(0, 0) + 13
a 7 "13" 5 returns point(7, 5) + 13
wait how is the first function call valid when the first argument must be int
and you put string
or it just skips the first arg?
first arg of a is int, i cast it to string and pass it to b
yes but why a "13" is possible when first argument of function a must be int
i meant to do a 13
was looking at signature of b when i wrote that so i wrote "13"
oh okay
Interesting
literally so good
I'll definitely use this
fun main() {
i64 a = 18;
{
i64 a = 7;
a = 9;
{
a = 8;
a = 10;
}
}
return a;
}
neat
will a be 18
yeah it should return 18
Or echo $status if you have fish :D
when you do echo $? in fish it'll say you that you have to use $status
lmfao
i dont like fish
I mean it's better than just saying it doesnt work, check docs
i used it for a bit and it not being posix is so annoying
do you use bash, zsh or something totally different?
time to make my own shell with blom 
terry davis moment
zsh
i use zsh
when elle shell
soon!!
isnt zsh the mac default
it does everything i want why change it
I'm using voidlinux
how is it?
xbps-query insane
also like their docs, clean, simple, straightforward
can you get softlocked like on arch
i used it for a few weeks
if you update specific dependencies and not pacman -Syu when you first install the OS
its awesome but i missed the aur
yeah that's the only thing I miss but I just created my own pkg repo
they have pretty similar format
if u mess smth up u just boot with live usb and fix it, i havent had to do that for > 6 months
lol fair
idk actually I never had issues
last time i tried arch it was on my ipad
oh on that note have you guys ever tried alpine
u can get "softlocked" anywhere if u try, arch is just the one everyone calls hard and unstable
in docker
nope because I have nvidia
why not asahi
but I use wayland anyways heh
Yeah on a really old laptop
It actually ran really well
this is my ipad
nvidia shouldnt be an issue anywhere anymore
Somehow got Firefox to open with like 512mb of ram
idk i know they have open source drivers if you mean that
cursed or good
yes why are u emulating x86 instead of running asahi
when git push
its on ios 18
its not jailbroken
nah the oss ones arent good yet
if i could run asahi i probably would
then how did u install alpine
iSH
does ios have vms
it does but theyre painfully slow because no virtualization
(because no JIT because apple sucks)
basically yes
qenq why do they not allow jit
@valid jetty do you allow nested functions?
only lambdas
expression = function | definition | op0 | if_expr ;
function = "fn" IDENTIFIER { TYPE } ;
definition = IDENTIFIER { PATTERN } "=" expression ;
if_expr = "if" expression expression "else" expression ;
op0 = op1 { IDENTIFIER op1 } ;
op1 = op2 { IDENTIFIER op2 } ;
op2 = op3 { IDENTIFIER op3 } ;
op3 = op4 { IDENTIFIER op4 } ;
op4 = op5 { IDENTIFIER op4 } ;
op5 = op6 { IDENTIFIER op6 } ;
op6 = op7 { IDENTIFIER op7 } ;
op7 = op8 { IDENTIFIER op8 } ;
op8 = op9 { IDENTIFIER op9 } ;
op9 = primary { IDENTIFIER primary } ;
primary = "true" | "false" | "null"
| "(" expression ")"
| NUMBER | STRING | IDENTIFIER ;
TYPE = IDENTIFIER ;
PATTERN = "_"
| "true" | "false"
| NUMBER
| STRING
| IDENTIFIER ;
@valid jetty rate
@placid cape rate
0..100 map (if (%3) == 0 "fizz" else "" + if (%5) == 0 "buzz" else "") each print
partial application is so awesome, (%5) returns a function similar to this:
def s(arg: int) -> int:
return arg % 5
overall equivalent to
def s5(arg: int) -> int:
return arg % 5
def s3(arg: int) -> int:
return arg % 3
def ss(arg: int) -> int:
return if s3(arg) == 0 "fizz" else "" + if s5(arg) == 0 "buzz" else ""
map(0..100, ss)
real?
So you have that if some_fn ... turns into |x| if some_fn(x) ...?
yes
What if you also need x inside the cases, make an explicit lambda?
Very often?
to make tuples
Often you do things like if x%2 then 3*x+1 else x/2
no lol it doesnt use env
im not gonna push that yet
im just refactoring all of my examples to use the new semantics
if (%2) != 0 ((*3)+1) else (/2)
oh okay
for now ill make it just not free anything at all
it is ugly so explicit lambdas will be allowed
bad but i dont wanna commit too much at once
but it's better to commit more often than one large commit that changes a lot of things
you can create local commits and then push everything at once
this commit alone edits so much stuff
yeah i know but my brain doesnt work like that lol
so you'll still have nice git history and also the version on GitHub will really work
i just kinda edit things all over the place
nested read full commit
literally
@placid cape if youve ever read my commit history
yea I've seen that
its bad but its just how my brain works
oh and i also accidentally fixed the issue with struct names being written twice lol
in old code you had to write
Foo foo = Foo { x = 1, y = 1 };
i was gonna make it so you can do
Foo foo = { x = 1, y = 1 };
that's nice
c moment
but then let came along so you can just do
let foo = Foo { x = 1, y = 1 };
Do you have support for function overloading?
nope
can u finally do
Fein fein = Fein { fein = fein, fein = fein };
lol you can actually do that
im not sure exactly what youre referring to but i have used it before in some form
function add(a: number, b: number): number;
function add(a: string, b: string): number;
function add(a: unknown, b: unknown): number {
if (typeof a === "string" && typeof b === "string") {
return Number(a) + Number(b);
} else if (typeof a === "number" && typeof b === "number") {
return a + b;
}
return 0;
}
๐
and if you have overloading with different amount of arguments you have to check for length of args as well
horrible
if you wanna call this overloading
i couldve used die actually
i forgot i have that function
but you dont get an error message with that
the meta struct is actually like super useful
the
i suppose this is an "env" of sorts
but its not passed to every function
only functions that ask for it
i have an idea
if a function produces side effects its not allowed to return a value
revised i guess
use std/prelude;
fn add(ElleMeta meta, ...) {
variadic args[meta.arity];
if meta.arity != 2 {
io::panic("Invalid number of arguments provided: {}", meta.arity);
}
let valid = ["string", "i32"];
if !valid.contains(meta.types[0]) || !valid.contains(meta.types[1]) {
io::panic("Invalid argument types provided: {} and {}", meta.types[0], meta.types[1]);
}
let a = meta.types[0] == "string" ? i32::parse(args.yield(string)) : args.yield(i32);
let b = meta.types[1] == "string" ? i32::parse(args.yield(string)) : args.yield(i32);
return a + b;
}
fn main() {
io::dbg(add("13", "26")); // valid
io::dbg(add(44, 6)); // valid
io::dbg(add(1, "99")); // valid
io::dbg(add("a", 13)); // valid because a would parse to 0
io::dbg(add(1.0, 3)); // invalid because f32
io::dbg(add(1, 2, 3)); // invalid because > 2 args
io::dbg(add("1")); // invalid because < 2 args
}
this is extremely cursed
who needs https://github.com/JakeLin/SwiftLanguageWeather when you got this
you also get no type validation at compile time on this lol
it lets you pass absolutely anything
technically this is a dynamic language now
its becoming closer and closer to js every day
i think i need to revise my function syntax
cause variables use the fn keyword
oopsie
way too long
๐ญ
this is cool tho
this looks like one of those "can you write a hello world script in the most convoluted way possible" things you get back from ai lmfao
yeah lol i just asked chatgpt "make long hello world script now"
add int int = a b $ a + b
add int int
add a b = a + b
// variable:
x = 7
fein fein;
fein fein(fein fein, fein *fein) {
fein fein fein = fein; fein < fein; fein += fein {
fein::fein("fein[%fein] = %fein", fein);
}
fein fein;
}
is this valid elle
i wish
omg i have an idea
// functions:
add int int = a b $ a + b
add int int
add a b = a + b
// variables:
x int = 7
x int
x = 7
๐
this is literally perfect
and to infer types
x := 7
// or (cursed??)
x _= 7
@valid jetty which one
x _ = is literally _ as the type
but x := is cleaner
const mitochondria = 'powerhouse of the cell'
_= would be consitent with function pattern matching
i guess
@placid cape ๐ญ
x int = 7
x _ = 7
because x is technically a function
technically the behavior isnt exactly the same because in js all numbers are floats
lmao ๐ญ
exactly
@valid jetty i think im gonna do _=
you can but it looks a little weird
ik
x _ = 7
add int int _ = a b $ a + b
it matches functions
i cant use : for pattern matching/inference
you could always just interpret : as a different thing depending on the context
i kinda feel like when reading it, _= looks more understandable, maybe ill think about it later
are you planning to use rust for lists or implement the recursive tail lists with Pair(done, next)
(the fp way of lists)
a list like [1, 2, 3] in fp would look like (1, (2, (3, nil)))
they can
how
In linear time
that was my point
its basically just a glorified singly linked list lol
id rather have [1, 2, 3]
It's not even glorified
or both, but first [1, 2, 3]
It is a linked list, plain and simple
theres usually abstractions over it to make it look like a conventional list
but yeah
In haskell it'd look like [1, 2, 3]
yeah thats what i meant
its sugar for a linked list
yep
It would really be 1:2:3:[], but syntax sugar is nice
but u cannot afford O(n) indexing when half of all problems are 2d grids
Fair
@hoary sluice is this a good feature
use std/io;
fn main() {
io::assert('a' == "a", nil); // Will use 'a' == "a"[0]
io::assert("a" != 'b', nil); // Will use "a"[0] == 'b'
io::assert("a" == 'a', nil); // Will use "a"[0] == 'a'
io::assert('a' == "abc", nil); // Will use 'a' == "abc"[0]
io::println("All string to character tests have passed!".color("green").reset());
}
``` i implemented this 3 months ago according to git blame
why io::assert
wdym
no
That sounds terrible
idk assert in io is weird
when ===
and yeah dont make JS lol
i spent 2 hours debugging why this wasnt working
it was because i typed ":" not ':'
Type errors, anyone?
sure
fn equals(a: any, b: any) {
if typeof a != typeof b return false
return a == b
}
now it passes analyzer and compiles
time to remove ==, just use .equals() everywhere 
java java java
fn js(a, b) {
return type(a) != type(b) || a == b;
}
sorry i meant operator fn ==
tomato potato
wait what
That's not null safe, the cool kids use Objects.equals()
technically here you can use generics lol
thats wrong
oh god
It's js-style equality
Object.requiresNonNull(a.equals(b))
fn equals<T, U>(ElleMeta meta, T x, U y) {
return meta.types[0] == meta.types[1] || x == y;
}
boolean is never null though
if the types arent equal return true?
i meant Object.requiresNonNull(a).equals(Object.requiresNonNull(b))
That's the way the nutshell crumbles
where do you draw the line
fn main() {
i32 x = 5;
i64 y = 10;
if (i64)x == y {
io::dbg("evil");
}
}
Yeah that's legit
does it actually do tha
No, it's slightly simplified
But a close approximation
a!! == b!!
kotlin ๐ฅฐ
Don't understand why you didn't make it, you already have compile time functions heh
thats not an implicit cast
you explicitly tell it to do that before doing the ==
oh i know but i meant the compiler does that for you
i meant dont cast inside the == at all
do you want the compiler to error when comparing i32 and i64
yes
horror
do you have default int as i32 or i64?
i32
So i64 a = 5; is also an implicit cast
no actually
default to usize ๐ง
That's also what go does
don't cast in if statements
in i64 a = 5 the compiler tells the literal that the type is i64 and it actually directly creates the literal as an i64
its what everyone besides js does
well yea but it's still a sort of "casting" but compile time
that's what I'm gonna do too
maybe stuff like ruby does casting in ==
its a bit cursd to read
ValueKind::Number(val) => {
let num_ty = match kind {
TokenKind::BoolLiteral => Type::Boolean,
TokenKind::IntegerLiteral => Type::Word,
TokenKind::FloatLiteral => Type::Single,
TokenKind::LongLiteral => Type::Long,
_ => Type::Word,
};
let mut final_ty = if ty.clone().is_some_and(|ty| !ty.is_string()) {
ty.unwrap_or(num_ty)
} else {
num_ty
};
if is_return {
final_ty = func.borrow_mut().return_type.clone().unwrap_or(final_ty);
}
Some((
final_ty.clone(),
Value::Const(
if final_ty.clone() == Type::Double {
"d_"
} else if final_ty.clone() == Type::Single {
"s_"
} else {
""
}
.into(),
val,
),
))
}
``` but yeah
struct A {
i32 a;
Point b;
}
struct B {
i32 a;
Point b;
}
let a = A { 3, Point { 4, 6 } }
let b = B { 3, Point { 4, 6 } }
assert a == b
this should fail
yeah but theres a difference because if you do
i32 x = 5;
i64 y = x:
``` it will promote x to i64 at runtime
and so should i32 vs i64
uhhhhh
idk i quite like being able to do
for x in [[1, 2], [3, 4]] {
if x == [1, 2] {
io::println(":3");
}
}
kotlin would require .toLong()
Yea ๐
It should fail to compile, even
This is deep equal
and thats how it behaves
one of the reasons why i cant just change all my points to long and have it work immediately
yes it is
yes
fn Array::__equals__<T>(T[] self, T[] other) -> bool {
if (void *)self == (void *)other {
return true;
}
if ((void *)self == nil) || ((void *)other == nil) || self.len() != other.len() {
return false;
}
for let i = 0; i < self.len(); i += 1 {
if self[i] != other[i] {
return false;
}
}
return true;
}
same type
thats enforced by the generics
can you do [1, 2] == ["1", "2"] ?
because that should throw compilation error
since it's a different type
just do it like java
bool ==(Object a, Object b) {
return &a == &b
}
it is false but the generic system actually fails here ๐ญ
the reason it doesnt throw an error is because T[] is Array<T> *, theyre both ptrs
once it looks at T[] for self and sees T = i32 it stops searching because it found all the generics
so it doesnt assert that the T in other is the same as the the T in self
i need to fix that
Array<reified T>
arr1.T.type == arr2.T.type
it basically interprets string[] as i32[] implicitly here but that is a huge issue lmfao
u have reified generics right?
uhhh only with ellemeta
fix that
eventually
if you're comparing objects with generics in java is casting mandatory?
it does actually fail here but these arent structs
hm? im not sure
I think you must
like you can't do
record Something<T>()
Something<Integer> a = new Something();
Something<Float> b = new Something();
a == b // error
oh yeah you deffo cant do that
i can actually technically do a little bit of a cursed thing
fn Array::__equals__<T, U>(ElleMeta meta, T[] self, U[] other) -> bool {
if (void *)self == (void *)other {
return true;
}
if ((void *)self == nil)
|| ((void *)other == nil)
|| self.len() != other.len()
|| meta.types[0] != meta.types[1]
{
return false;
}
for let i = 0; i < self.len(); i += 1 {
if self[i] != other[i] {
return false;
}
}
return true;
}
oh and it actually fails at compile time now
ok good
please either remove ellemeta, rework it ar maket implicit with self.meta
But what if you have meta in struct
yeah that
ok this is probably good
fn Array::__equals__<T, U>(T[] self, U[] other) -> bool {
// If the pointers are the same (nil == nil)
if (void *)self == (void *)other {
return true;
}
// If one is nil
if ((void *)self == nil) || ((void *)other == nil)
|| self.len() != other.len() // If lengths don't match
{
return false;
}
if !self.is_empty() && !other.is_empty() {
if self[0] != other[0] {
return false; // If the types don't match
}
}
for let i = 0; i < self.len(); i += 1 {
if self[i] != other[i] {
return false; // Deep equality
}
}
return true;
}
making meta restricted keyword is too much tbh
yeah you can call the meta struct whatever you want
u dont need this
you actually dont need ElleMeta for this because itll fail at compile time if the types of the arrays dont match
why are u panicking when hitting an error
thats a thing i meant to solve a while ago but never got to
esp in lexer
without an lsp
u have to compile so many times to find syntax errors
is it actually faster than the npm pkg?
im guessing fast deep equal is faster
Just asking because last time when I implemented own reduce it was faster lol
- maybe
- why does it matter lol
in 99.99% of scenarios it doesnt matter if it's slightly slower
couldnt that be use for web?
what if im writing a binary protocol and i want to assert that the UInt8Array i got from the client matches what i would expect
and the UInt8Array has 1,000,000,000 items inside
then you wouldnt use deepEqual
lmfao ok
you would compare the arrays
- just asking
unicode 
NO
no???
why you're changing your static typed language to dynamic

oh x is a string
i remember spending so long trying to get that to work lol
yea its file
thats not dynamic
fine
wdym lol
you can do x ?: "meep"
equivalent to x ? x : "meep"
|| was a feature longgggg before ?:
thats for nulls only in kotlin
isnt that intended
yeah yeah I'm stupid
no it was interpreting 1 as a string and failing at compile time
because it thought 1 was a char *
huh lol
yeah it was weird
its like when doing
fn foo(i32 c) {}
foo(bar(bar("a"));
``` it thought "a" is an i32 lol
oh lol
thankfully that was fixed because wtf
btw you have to do the block jmps for those
because you have to implement short circuiting
like in x && y if x is false it shouldnt even evaluate y
meh
or in x || y if x is true it shouldnt evaluate y
oh yea
it's in the first line
oh
Cannot implicitly convert 'i32' to 'string'
the colored thing should have it too tho
yeah idk i can color in i32 and string to make it stand out more
@hoary sluice is stuff like this ever useful for aoc
use std/vectors;
use std/prelude;
fn Vector3::test() {
let v = Vector3 { x = 1.0, y = 0.0, z = 0.0 };
let axis = Vector3 { x = 0.0, y = 0.0, z = 1.0 };
let angle = PI / 2.0;
let rotated = v.rotate(axis, angle);
io::dbg(rotated);
let v1 = Vector3 { x = 1, y = 0, z = 0 };
let v2 = Vector3 { x = 0, y = 1, z = 0 };
io::dbg(v1.angle(v2));
let zero = Vector3::zero();
io::dbg(zero);
}
fn Vector2::test() {
let v1 = Vector2 { x = 1.0, y = 0.0 };
let rotated = v1.rotate(PI);
io::dbg(rotated);
let v1 = Vector2 { x = 1, y = 0 };
let v2 = Vector2 { x = 0, y = 1 };
io::dbg(v1.angle(v2));
let zero = Vector2::zero();
io::dbg(zero);
}
fn main() {
Vector3::test();
io::println();
Vector2::test();
}
i swear ive asked about these vectors before actually
short term memory loss
yes extremely
technically point is (i32, i32)
no lol
theres only io::read_to_string() as a temporary thing for aoc
fn io::read_to_string(string path) -> string {
FILE *file = io::fopen(path, "r");
defer io::fclose(file);
if !file {
return nil;
}
io::fseek(file, 0, SEEK_END);
i64 file_size = io::ftell(file);
io::fseek(file, 0, SEEK_SET);
i64 buf_size;
if file_size > 0 {
buf_size = file_size + 1;
} else {
buf_size = 4096;
}
string buf = (string)malloc(buf_size * #size(char));
if !buf {
return nil;
}
i64 pos = 0;
i64 read_size;
while (read_size = io::fread(buf + pos, #size(char), buf_size - pos - 1, file)) > 0 {
pos += read_size;
if pos >= buf_size - 1 {
buf_size *= 2;
buf = (string)realloc(buf, buf_size * #size(char));
if !buf {
return nil;
}
}
}
buf[pos] = '\0';
return buf;
}
And vector2 is f32?
yes
Make Vector2f and Vector2d
oh they are floats
i could make Vector2::from<T>((T, T) x)
idk they are vectors
FPoint
that's aoc specific thing
or FloatPoint
like in math they are vectors
fn Vector3::zero() {
return Vector3 {
x = 0,
y = 0,
z = 0
};
}
fn Vector3::clone(Vector3 self) {
return Vector3 {
x = self.x,
y = self.y,
z = self.z
};
}
fn Vector3::dot(Vector3 self, Vector3 v2) {
return self.x * v2.x + self.y * v2.y + self.z * v2.z;
}
fn Vector3::cross(Vector3 self, Vector3 v2) {
return Vector3 {
x = self.y * v2.z - self.z * v2.y,
y = self.z * v2.x - self.x * v2.z,
z = self.x * v2.y - self.y * v2.x,
};
}
fn Vector3::length_sq(Vector3 self) {
return self.dot(self);
}
fn Vector3::length(Vector3 self) {
return math::sqrt(self.length_sq());
}
fn Vector3::add(Vector3 self, Vector3 v2) {
return Vector3 {
x = self.x + v2.x,
y = self.y + v2.y,
z = self.z + v2.z,
};
}
fn Vector3::sub(Vector3 self, Vector3 v2) {
return Vector3 {
x = self.x - v2.x,
y = self.y - v2.y,
z = self.z - v2.z,
};
}
fn Vector3::scale(Vector3 self, f32 scalar) {
return Vector3 {
x = self.x * scalar,
y = self.y * scalar,
z = self.z * scalar,
};
}
fn Vector3::normalize(Vector3 self) {
f32 length = self.length();
return self.scale(1.0 / length);
}
they behave like vectors in math
yea that's good keep it
