#๐ช -progaming
1 messages ยท Page 30 of 1
theyre useful for my graphics examples
ok then its fine
for let theta = 0.0; theta < 2 * PI; theta += THETA_SPACING {
f32 sinTheta = math::sin(theta);
f32 cosTheta = math::cos(theta);
for let phi = 0.0; phi < 2 * PI; phi += PHI_SPACING {
f32 sinPhi = math::sin(phi);
f32 cosPhi = math::cos(phi);
let surfacePos = Vector3 {
x = cosPhi * (cosTheta + 2),
y = sinPhi * (cosTheta + 2),
z = sinTheta,
};
let depth = 1 / (surfacePos.y * sinRotX + surfacePos.z * cosRotX + 5);
let projectionOffset = surfacePos.y * cosRotX - surfacePos.z * sinRotX;
i32 x = 30 + 36 * depth * (surfacePos.x * cosRotZ - projectionOffset * sinRotZ);
i32 y = 12 + 12 * depth * (surfacePos.x * sinRotZ + projectionOffset * cosRotZ);
i32 offset = x + WIDTH * y;
let normal = surfacePos.clone();
let normalLengthSquared = normal.length_sq();
if normalLengthSquared > 0 {
normal = normal.scale(1.0 / normalLengthSquared);
}
let illumination = normal.dot(*lightDirection);
let lightingIndex = (i32)(math::abs(illumination) * (LIGHTING.len() - 1));
if HEIGHT > y && y > 0 && x > 0 && WIDTH > x && depth > zBuffer[offset] {
zBuffer[offset] = depth;
let lightingMapping = (i32)lightingIndex % (LIGHTING.len() - 1);
output[offset] = LIGHTING[lightingMapping < 0 ? 0 : lightingMapping];
}
}
}
``` i wrote the donut ascii thing from scratch using vectors
its useful to have
and then java: Vector is legacy ArrayList 
yeey
how
technically normal can be surfacePos.clone() i forgot thats a thing now
wdym how
did u steal a c impl
lmfaoo
theres a pseudocode impl at the bottom but that doesnt use vectors
or at least not directly
i think its also not an exact replica but it looks good enough
lmfao
i guess
i made it slower (its a little squished in ghostty)
shrug
mostly the lighting is broken i think
idk not thinking abt that rn
so many lol
technically prelude imports more things but the compiler sees that theyre already imported and doesnt go to import them again
ok @valid jetty it makes no sense for function declarations to be expressions
it really doesnt unless youre a pure fp lang
and functions are first class citizens of the language
not even haskell has that
and i made lambdas
creating lambdas is an expression
are they capturing
so it makes even less sense
i mean
a :: Int -> Int
isnt an expression
can you do like map (\x, y -> * x y) [(1, 2), (3, 4), (5, 6)]
that is not a lambda
that is a function declaration
and its not an expression
[(1, 2), (3, 4), (5, 6)] map (x y $ x * y)
ok yeah good
@placid cape try write this in blom
use std/io;
fn direction(i32 *other) -> bool {
return !other ? direction(&0) : &0 > other;
}
fn main() {
io::printf(
"The stack is growing {}wards for your architecture.",
direction(nil) ? "up" : "down"
);
}
function syntax is now
add int int _ $ x y = x + y
// or
add int int _
add x y = x + y
or u can inline with a lambda
the devious map<i32> in question
what is _ here
inferred type (int)
what is it inferring then
but yea
the return type ๐
๐ญ
fuck i forgot
there
ok i mean all the tests pass
ill run my aoc solutions to make sure they all pass but if they do then ill push
then i can continue working on the env
u could do smth like
otherfunc int int int int int int
// implement
abc int int _ _ _ _ $ x y = x otherfunc y
and variables are just
a int = 7
a _ = 7
which is why i wanted to use _
in elle the extent of inferring is
- inferring the return type based on the type of the values you return (checks to make sure there isnt more than 1)
letwhich basically gets rid of the lhs being used to infer information from the rhs (such as in Array::new<T>())- inferring in
for x in yloops (basically just sets the current value to useletinternally lol its the same mechanism)
oh
looks like it would be really confusing to debug
why thats just the same as
var a = 7
in kotlin
oh my god
true i guess
imo the way i do it is kinda nice maybe
let x = 1;
``` if it can be inferred, if you need to supply extra info such as in arrays you have 2 options
```rs
let arr = Array::new<i64>();
``` or
```rs
i64[] arr = [];
i dont like rust's way where you have
let x = 1;
``` or
```rs
let arr = Vec::new::<i64>();
or
let arr: Vec<i64> = vec![];
same in rust
no u dont

uhhh well i dont have pointers rn
yea
need to implement pointers
and compile time function is not only compile time anymore heh
ill rename them to builtins or something
oh in rust you actually cant even Vec::new::<i64>() it MUST be inferred from the type of lhs
Vec::new takes no generics
no
yes
Vec::<i64>::new()
oh thats evil
yeah i guess
yeah i know because rust is really good at inferring based on what you push into it or where you store it
ok well i mean i guess its time
i like to use github desktop when the commit is huge
wow
read full commit read full commit read full commit read full commit read full commit read full commit read full commit read full commit
meanwhile me git diff because zed doesn't have git integration 
same
thats the only thing i dislike abt zed
(and that it doesnt support jvm/kt)
just download gh desktop
nah i have vsc
oh
okay i should fix this heh
lol this is why i use gh desktop
expression = definition | if | lambda | op ;
definition = declaration | body ;
declaration = IDENTIFIER type { type } [ "$" { pattern } ] "=" expression ;
body = IDENTIFIER { pattern } "=" expression ;
lambda = "(" IDENTIFIER "$" expression ")" ;
if = "if" expression expression { "else if" expression expression } "else" expression ;
op = primary { IDENTIFIER primary } ;
primary = "true" | "false" | "null"
| "(" expression ")"
| NUMBER | STRING
| IDENTIFIER ;
type = "_" | IDENTIFIER ;
pattern = "_"
| "true" | "false"
| NUMBER
| STRING
| IDENTIFIER ;
i think this is final
op is all operators with their precedence (resolved at runtime)
exactly like noulith
this is funny xdd (compiled also includes start time)
now i can finally calculate euler's number :)
you can do this which i think is a bit silly
for i in (let res = 1)..=10 {
res *= i;
}
io::assert(res == 3628800, nil);
factorial
yay
i love this kind of stuff :3
great for golfing
are the {} still required
Hello, i keep getting a HTTP load failed with status 404. Load of media resource even though i have no such file? ๐ญ the file is called play-when-spotify-detected.mp4. this is how i call it:
i think it's bcs i renamed the file to have is but i don't know why it's still consistently asking for the old version.
i did it
what
read full commit read full commit read full commit read full commit read full commit read full commit
yep
now im gonna continue implementing the env (it wont use the actual qbe env because i wanna save that for closures)
because this is not it
lmfao
The browser is trying to load a file that doesn't exist
I don't know how to fix it
name the file the same?
Yea
its called is-detected
I think it's smth to do with audioPlayer.src, but when i tried to change it, it js used the same thing
not the same name
lmaooo
ok i pushed all my changes to my aoc solutions
i wanna try to get them all done before the new year aaaa
i have to do 7.5 days in 2 days
because day 25 only has 1 part and because its already 6pm
@valid jetty @placid cape is it horror if i store function names that have already been declared in my parser to disambiguate between function declarations and function bodies since theyre both just a bunch of identifiers
I'm saving all function names
map of name and declaration statement
but I'm doing it in my analyzer and compiler
maybe i should rethink my function syntax again
and I should rethink my compiler
I'll probably do something like rosie, creating another AST which will be more low level
mine does not create a more low level ast
it doesn't?
maybe i just need to accept that :: is inevitable
add : Int Int
add a b = a + b
fact : Int Int
fact 0 = 1
fact n = fact (n - 1)
and no same line body
thats too confusing
fn main() {
let x = 1 + 1;
}
Function {
name: "main",
arguments: [],
return_type: Some(Word),
blocks: [
Block {
label: "start",
statements: [
Assign(Temporary("x.addr.1764"), Pointer(Word), Alloc8(Const("", 4))),
Assign(Temporary("tmp.1762"), Word, Add(Const("", 1), Const("", 1))),
Volatile(Store(Word, Temporary("x.addr.1764"), Temporary("tmp.1762"))),
Volatile(Return(Some((Word, Const("", 0), examples/test.le:1:8)))),
],
},
],
}
just a rust-based representation of the qbe
but at that point i might as well just use haskell ๐ญ
no ast here
haskell
i dont wanna make haskell without the ->
Oh I see
i see how you're doing it
I'm doing pretty much the same but worse
I'll rewrite the compiler again
wait ocaml, F# and ml are all related???????
I'm just generating strings
I'll also create enums etc for it to represent it better
its so hard to explain this lol
well let infers to the smallest possible size but not smaller than i32, or?
no, let basically gives the rhs no information about the type it should be, so 0 becomes the default integer literal size which is i32
oh okay
https://slopify.dev/ this is literally 2000s esque
youtube running in chromium running in your terminal
WHAT IS THAT LINK
github content from private repository
So it contains jwt
its not private tho
then idk why it has jwt lol
yeah idk
github copied the link weird
LMAO THE FOURIER TRANSFORM IS IN JAPANESE https://ja.wikipedia.org/wiki/ใใผใชใจๅคๆ
ๆฐๅญฆใซใใใฆใใผใชใจๅคๆ๏ผใใผใชใจใธใใใใ่ฑ: Fourier transformใFT๏ผใฏใๅฎๅคๆฐใฎ่ค็ด ใพใใฏๅฎๆฐๅค้ขๆฐ
f
{\displaystyle f}
ใใๅฅใฎๅ็จฎใฎ้ขๆฐหfใซๅใๅคๆใงใใใ
ๅทฅๅญฆใซใใใฆใฏใๅคๆๅพใฎ้ขๆฐหfใฏใใจใฎ้ขๆฐ
f
{\displaystyle f}
ใซๅซใพใใๅจๆณขๆฐใ่จ่ฟฐใใฆใใใจ่ใใใใฐใใฐใใจใฎ้ขๆฐ
f
{\displaystyle f}
ใฎๅจๆณขๆฐ้ ๅ่กจ็พ (frequency domai...
@hoary sluice
This is just weird heh
Mixing Japanese chars with latex
its mostly kanji because theyre technical terms
idk ii dont know japanese
gonna create another module called qbe which will have all definitions/enums for qbe
and then the compiler will just use them like yours
thats a way better
you might find this useful https://github.com/garritfra/qbe-rs
thx
i also looked for golang ones but didnt find anything maintained so i'll do my own
i used it as a reference in the begining but now mine is completely different lol
so its okay
idk if you wanna read through it https://github.com/acquitelol/elle/blob/rewrite/src/compiler/enums.rs
its a mess
package qbe
import (
"errors"
"fmt"
"slices"
)
type Type int
const (
UnsignedByte Type = iota
UnsignedHalfword
UnsignedWord
UnsignedLong
Byte
Halfword
Boolean
Word
Long
Single
Double
Char
String
Void
Null
)
var humanTypes = []string{
UnsignedByte: "u8",
UnsignedHalfword: "u16",
UnsignedWord: "u32",
UnsignedLong: "u64",
Byte: "i8",
Halfword: "i16",
Boolean: "bool",
Word: "i32",
Long: "i64",
Single: "f32",
Double: "f64",
Char: "char",
String: "string",
Void: "void",
Null: "null",
}
var types = []string{
UnsignedByte: "ub",
UnsignedHalfword: "uh",
UnsignedWord: "uw",
UnsignedLong: "ul",
Byte: "b",
Halfword: "h",
Boolean: "w",
Word: "w",
Long: "l",
Single: "s",
Double: "d",
Char: "c",
String: "l",
Void: "",
Null: "",
}
func ParseType(str string) (Type, error) {
index := slices.Index(humanTypes, str)
if index == -1 {
return 0, errors.New(fmt.Sprintf("Unknown type '%s'", str))
}
return Type(index), nil
}
func (t Type) HumanInspect() string {
return humanTypes[t]
}
func (t Type) String() string {
return types[t]
}
func (t Type) IsNumeric() bool {
return t.IsInteger() || t.IsFloatingPoint()
}
func (t Type) IsInteger() bool {
return t == UnsignedByte || t == UnsignedHalfword || t == UnsignedWord || t == UnsignedLong || t == Byte || t == Halfword || t == Word || t == Long
}
func (t Type) IsFloatingPoint() bool {
return t == Single || t == Double
}
my types
well actually char, str, boolean, void and null shouldnt be there
i took that from yours
its also in Kadazandusun https://dtp.wikipedia.org/wiki/Ponimban_Fourier
Ponimban Fourier nopo nga' iso ponimban donsompuu (integral transform) it ogumu kopio ampos toi kounalan id mogikaakawo gana' lobi po id pongumbangan pandu dontuntuu (digital signal processing).
Ponimban diti poposimban do pandu mantad raung hiza (time domain) kumaa raung sinaru (frequency domain).
char be c that doesnt exist
char is different from i8 for me because it displays differently
char displays with %c i8 displays with %d
does elle make a distinction between primitiver and structr
omg its so annoying when s is next to r
looks so silly
structs are a primitive
oh
oh
yes
in general the convention is that structs are capitalized and primitives arent
how about caps are a compilation error
nono you can define structs just like any identifier
its how i plan to add i128 support when i add dunder methods for add sub mul div
i want to make caps illegal
use std/prelude;struct FEIN{i8 _;};
fn FEIN::__equals__
(FEIN
FEINN
,FEIN
FEINNN){
return
FEINN
._==
FEINNN
._;}fn
FEIN_FEIN
(FEIN FEINN
,FEIN
FEINNN){
io::dbg(
FEINN
== FEINNN ?
"FEIN": "FEIN"
);}fn
main
() {
let
FEINN=FEIN{_
=39 };let
FEI = FEIN
{_ =
39 }
;FEIN_FEIN(FEINN
,FEI);}
grammar.ebnf:
expression = body | declaration | if | lambda | op ;
body = IDENTIFIER { pattern } "=" expression ;
declaration = IDENTIFIER ":" type { type } ;
if = "if" expression expression { "else if" expression expression } "else" expression ;
lambda = { IDENTIFIER } "$" expression ;
op = primary { IDENTIFIER primary } ;
type = "_" | IDENTIFIER ;
pattern = "_"
| "true" | "false"
| NUMBER
| STRING
| IDENTIFIER ;
primary = "true" | "false" | "null"
| "(" expression ")"
| NUMBER | STRING
| IDENTIFIER ;
thats not the best way to do that lol
please tell me this is valid
theres ebnf syntax highlighting???
but there's no better way in go
hello = omg
or am i missing something?
is this ur ast
it is ๐ญ
i dont have location in tokens
you may wanna report the error of a whole node instead of just a token
how do u report lexer errors then
this ^
i lied that is the best way because thats go
yep otherwise i would use enum w/ values
the error will be recognizably close if you just have it in the token, no?
also consider most nodes dont contain tokens
@placid cape perfect timing https://youtu.be/xSyUvkpHv6M
I love Arch Linux and I always will so when I came across this survey on the Arch Linux subreddit I knew I had to go through it and talk about my experience on Arch.
==========Support The Channel==========
โบ Patreon: https://brodierobertson.xyz/patreon
โบ Paypal: https://brodierobertson.xyz/paypal
โบ Liberapay: https://brodierobertson.xyz/liberap...
lol
yes they do
im not gonna use archlinux anymore
tokens where
or at least nested
i broke my whole system just by installing mysql package
wtf is that where are ur tokens
im not gonna traverse a huge ast to find the tokens
this isnt aoc
there are some with tokens
literals arent statements theyre just called that because i was silly when i wrote that
speaking of statements
actually no this ast is completely wrong
doesnt match my grammar
so can every other ide
this is new to me after using vanilla nvim for a while
(how do u do it in zed tho)
right click on ident -> rename symbol
just do x and y
no
vesktop, zed, google chrome
yes, google chrome on linux
and youtube music with auto play
this is most I need
nice
what do u use for calculator
use std/prelude;
fn main() {
// Ranges create arrays for the time being
io::assert(5..10 == [5, 6, 7, 8, 9], nil);
io::assert(3..=8 == [3, 4, 5, 6, 7, 8], nil);
for i in (let res = 1)..=10 {
res *= i;
}
io::assert(res == 3628800, nil); // 10! (factorial)
io::println("All range tests have passed!".color("green").reset());
}
``` this runs in <1ms suprisingly
lightning man was right
thats fast wtf
python or node or google search or wolfram alpha
its 10! itd be very bad if that took longer than a ms
when i need to calculate something i just open kitty (terminal)
what abt bluetooth, wifi
ok hear me out
networkmanager, blueman
and for screenshots i have bindsym Mod4+Shift+s exec sh -c 'filename="/tmp/$(date +%F_%T).png"; grim -g "$(slurp)" "$filename" && wl-copy < "$filename"'
idk i spent like a year on hyprland and at some point just had enough of the various things that a de has that a wm doesnt; calculator, bluetooth / wifi gui, consistent theming (dont have to mix gtk and qt apps)
send ur config
background-opacity = 0.7
background-blur-radius = 30
theme = catppuccin-mocha
font-family = Maple Mono
window-padding-x = 16
window-padding-y = 16
window-height = 26
window-width = 90
you can get rid of it
ok now its awesome
the ultimate minimalistic setup
idk i like swayfx, it's minimalistic and simple
the neferious macos:
oh the blur doesnt work on non-macos
hmm maybe ill try ghostty, kitty works and is nice
oh well
i have been suffering with this title bar for weeks, i couldnt find the config option for it, pretty sure it was merged recently
okay instruction &ย comparison done
wtf
ok well this was opened 3 days agohttps://github.com/ghostty-org/ghostty/discussions/3158
2 weeks ago there was nothing
idk maybe it was an option but not documented
it was
i looked up remove title bar
there were a few people saying to set some env variables
is it time for day 18 in elle
didnt work
i did it with A* ๐ญ
oh the padding is nice
at least i have these extensions now
fn Array::heap_pop<T>(T[] pq) -> T {
if pq.is_empty() {
return nil;
}
let result = pq.first();
pq[0] = pq.last();
pq.pop();
let i = 0;
while true {
let smallest = i;
let left = 2 * i + 1;
let right = 2 * i + 2;
if left < pq.len() && pq[left].x < pq[smallest].x {
smallest = left;
}
if right < pq.len() && pq[right].x < pq[smallest].x {
smallest = right;
}
if smallest == i {
break;
}
let temp = pq[i];
pq[i] = pq[smallest];
pq[smallest] = temp;
i = smallest;
}
return result;
}
fn Array::heap_push<T>(T[] pq, T value) {
pq.push(value);
let i = pq.len() - 1;
while i > 0 {
let parent = (i - 1) / 2;
if pq[parent].x <= pq[i].x {
break;
}
let temp = pq[i];
pq[i] = pq[parent];
pq[parent] = temp;
i = parent;
}
}
ya it makes it way nicer imo
why not make proper queues
effort
these functions also kinda assume that T is a tuple where T.x is comparable but whatever lol
not necessarily a tuple but any struct with a comparable x field
@valid jetty @placid cape this is so useful
what ๐ญ
I had that installed for years but found that I never used it so I nuked it
its not unmaintained its just completed, perfect and doesn't need maintaining
true
@valid jetty i literally breathe aoc and this is how i made a huffman code
notice how that is not a huffman code
๐ญ
Ive solved like 50 aoc problems that involve a priority queue but on a test i think that 3+4 <= 2+3
LMAO literally me
ive written > 10 implementations of bubble sort and quick sort in at least 4 languages but ask me to implement one in pseudocode during an exam and i wont be able to
chatgpt is bad at plugins
i think i was born at the right time, old enough to have started with java and shitty ides and young enough to see my classmates do their entire thesis with chatgpt while being completely clueless
"import { Plugin } from 'vencord'; LOL
elle wasm
it cant compile to wasm
qbe doesnt do wasm??
https://eigenstate.org/notes/wasm but this post is not from the qbe author I think
Why Web Assembly is Not My Favorite Compilation Target
-t <target> generate for a target among:
amd64_sysv, amd64_apple, arm64, arm64_apple (default), rv64
ah, this bullshit
llvm supports wasm but thats llvm
I've seen this same complaint when looking at QBE a week ago
to see how difficult it'd be to make a custom backend
I noticed someone asking about Wasm on the Sourcehut mailing list
if you guys wanna look at me being confused for 8 months lol https://lists.sr.ht/~mpu/qbe?search=Rosie
I think the runtime authors have specified that not having this makes their lives easier
and like
Just use Binaryen's Relooper
cfg/Relooper.h
xdd
I also have sourcehut
anyways, this "issue" isn't Wasm's problem
to be fair nested loops are somewhat confusing with labels and goto
export function w $main() {
@start
@loop.5.cond
jnz 1, @loop.5.body, @loop.5.end
@loop.5.step
jmp @loop.5.cond
@loop.5.body
@loop.6.cond
jnz 1, @loop.6.body, @loop.6.end
@loop.6.step
jmp @loop.6.cond
@loop.6.body
jmp @loop.6.step
@loop.6.end
jmp @loop.5.step
@loop.5.end
ret 0
}
I believe it'd also be pretty garbage for validation
wow nice
because blocks can have results on the stack
did you ever try reading qbe source code
nope
nice for portability
taster
but ```c
static void
func(Fn *fn)
{
the shit that bugs me the most is probably the naming
no offense to qbe devs but what is this
C99 probably doesn't support block-scoped variables?
but what the fuck is with their naming
Fun fact: types can have more than 3 letters
Not that I'm one to speak
HUHHH?
I mean, still better than 7zip
its a linked list of function pointers
oh lord
they have limited identifier length like qbe itself
but qbe at least supports 60 chars 
The width of a terminal is 80
but with a tab or two (depending on tab width), someone might use 72
okay im back on computer
its 80
analyzer finally doesnt use compiler, dont ask why it uses it
๐
oh btw did i show you guys this yet
mandelbrot set in elle
written rendering to a texture at 1/4 resolution to maintain a decent framerate ๐ซ
thats cool :D
woah
ok this is valid so i have an idea
data $c = { l 0, l 0 }
data $formatter = { b "value is %ld\n", b 0 }
export function w $main() {
@start
storel 1, $c
%f =l loadl $c
call $printf(l $formatter, ..., l %f)
ret 0
}
ill make a #env directive which goes and loads the value at some global data section and interprets it as a region allocator
or well interprets it as an ElleEnv struct pointer
@hoary sluice @placid cape its so real
not passing anything to foo
it still allocates things
i turned args into real arg thing
use std/prelude;
fn main(string[] args) {
io::dbg(args);
}
go makes me want to tear my hair out
the build system and module/package system makes no fucking sense
all i want to do is build an executable
too confusing
Write Zig
never
Yeeey
lol it works but its slowwwww
im trying to change it to be an arena allocator but im getting stumped trying to free the nodes
There should be a separate channel for language dev or rename this one, because theres nothing else here being discussed lol
SO TRUE
i hate go
timezones?
also not that late to stay up
fr
shes an hour behind me and has been online the whole day yday
sleep is bloat
who needs sleep
another 1k lines 
@valid jetty @placid cape i figured out how to make everything an expression (function declarations as expressions)
id : T T -- generic function
f : Int Int Int
f g = g 42
x = f (id : Int Int) -- f takes Int Int, so id is typecast as Int Int since its generic
i think once i have inference this might only be useful for readability or specifying which generic types you want if youre passing id to another generic function
id : T T -- generic function
x = id : Int Int -- x is now id but can only take ints
this would actually be useful to specialize stdlib functions, maybe point.map requires deepcopying so you overload the map function for point specifically
cool
will your type system itself be turing complete like typescript? xD
Okay I guess I'll probably make the return value system of block expression/if expression same i as rust
it'll take the last statement
because I could rewrite return in these expressions to variable assignment but I don't want to do it
If return keyword means return from block, how do you return from function
@valid jetty have u seen the O(1) NP solver
labels
that's why I said I'll make it like in rust
hopefully not
if it is that also means im gonna have to solve an aoc day in icps types
and it would be really confusing
so this will return 9:
function mm() {
i32 a = if 5 > 3 { 4 } else { 7 }
return a + 5;
}
but if you do:
function mm() {
i32 a = if 5 > 3 { return 4; } else { return 7; }
return a + 5;
}
it'll return 4
are if else blocks equivalent to lambda blocks
well probably yea?
It's just expression
and all blocks
so same applies for
fun a() {
{
....
}
}
i32 a = {
i32 c = 6;
6 + 7
}
in kotlin if you return from an if {} block you return from the function, but if you return from a lambda {} block you return from the lambda
uh lol
I could do that but I would have to make two different returns - one if expression and one in statement
or i could replace return in expressions to assignment
Returning from an outside scope from a lambda requires either funny scoped lambdas, or callCC
I could also put everything into functions but I don't want to do that lol
hm wait
lambda is just a function and I don't threat function body as block expression
so that's okay
well I'll have the same behaviour as kotlin
scopes arent that complicated
when u enter a scope u make a new nested env and if an identifier is unresolved u go to the parent env
Yea I'm doing something similar in my interpreter
but it's a bit harder when you're generating code into IR
well maybe its not actually
lol this actually looks nice
i stayed up until 6am trying to debug why my fucking arena allocator was trying to dereference 0x10 when freeing all the arenas
and then i had to wake up at like 10am to go to an event thing
finally im home so i can debug it
i wouldve just stayed with my original region allocator but its slowwwwwwwwww
it takes like 275x longer to solve day 12 simply by using a different allocator
oh
at least now itโs setup in such a way where the allocator is abstracted away and i can just swap it out as needed
that's nice
compiler problems ๐ฅฑ
@valid jetty installing gh desktop crashes my system
Why even use that
cause the diffs look better than in the terminal
no lol thats what i do
yea i realized how stupid it is to mix value enums with normal enums
nice this is mine
๐
thats really clean lol
ok this is so weird
im making a bump allocator
this is FromIdentifier
it works
fn BumpAllocator::realloc(BumpAllocator *self, void *ptr, i32 new_size) {
if new_size <= 0 {
return nil;
}
if !ptr {
return self.alloc(new_size);
}
if ptr < self.buffer || ptr >= (void *)((char *)self.buffer + (char *)self.capacity) {
return nil;
}
i32 offset = (i32)((char *)ptr - (char *)self.buffer);
if offset + self.used == self.used {
if offset + new_size <= self.capacity {
self.used = offset + new_size;
return ptr;
}
}
void *new_ptr = self.alloc(new_size);
if new_ptr {
i32 copy_size = new_size;
if offset + new_size > self.used {
copy_size = self.used - offset;
}
if copy_size > 0 {
mem::memcpy(new_ptr, ptr, copy_size);
}
}
return new_ptr;
}
``` but for some reason in day 12 it ends up being unable to memcpy at some point
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfa677608)
* frame #0: 0x00000001875df0d8 libsystem_platform.dylib`_platform_memmove + 520
frame #1: 0x0000000100001d10 solution`BumpAllocator.realloc + 668
frame #2: 0x000000010001601c solution`Array.resize.0.2.HashSet.0.2.Tuple.0.11.11.1.1.1 + 92
frame #3: 0x00000001000160b0 solution`Array.push.0.2.HashSet.0.2.Tuple.0.11.11.1.1.1 + 92
frame #4: 0x0000000100017860 solution`__internal.elle.__main__ + 5968
frame #5: 0x0000000100017e7c solution`main + 572
frame #6: 0x0000000187287e50 dyld`start + 2544
if i had to guess im reallocating wrong
fuck i hate this
fmt.Sprintf fail 
is in better to use Option<TokenValue> or have None in the TokenValue enum?
๐โโ๏ธโโก๏ธ
real
uh probably none? idk
where do you want Option<TokenValue>
idk what the best way is but yeah
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ValueKind {
String(String),
Number(i128),
Character(char),
Nil,
}
address boundary error โค๏ธ
idk why it throws that error but its cool that it doesnt even try to run it since its just an infinite loop
stack overflow?
make proper error messages
this:
fn main() {
i32 a = 5;
a = 7;
return a;
}
produces
export function w $main() {
@start
%a.addr.57 =l alloc8 4
storew 5, %a.addr.57
storew 7, %a.addr.57
%a.58 =w loadw %a.addr.57
%a.58 =w loadw %a.addr.57
ret %a.58
}
why loading again?
you probably forgot to remove the loading instruction since identifier literal takes care of it
well sure but first i have to finish compiler :D
variable declarations are exprs
i need to load to return it from the expr
oh like when you do return a = 3 ?
it allows you to do like
print(a = 7) and the return value of a = 7 is the loaded value from a.addr even though you might load it again later with an identifier literal
theres not really a way to get rid of that second load other than optimization passes after the initial codegen
you have no way to know because of the recursive nature
you have no idea if where you are right now is at the top level as an stmt or 5 recursions deep as an expr
the way you determine whether a node is an expr or stmt is whether you return Some((ty, val)) or None from the codegen for it
but as variable declarations are an expr theyre always an expr
It's a bit weird that you have variable declaration and assignment as one token heh
but idk it's probably okay
is this for stuff like a = b = c = 3
yes
ignore the allocation stuff
the 1 is the important thing
let x = let y = 1 sets y to 1, then sets x to the value of y, then that itself is an expr so you get the value of x
this is weird xd
idk imo variable declarations being exprs is kinda fun
because then you can do this let x = (let y = 1) + 1;
now y is 1 and x is 2
or you can do ```rs
for i in (let res = 1)..=10 {
res *= i;
}
QBE probably optimizes it so it doesn't matter ig
what
but yeah this is extremely weird
@valid jetty when will elle transpile to malbolge
soon
my allocations are aligned wrong in the arena allocator and eventually it allocates incorrectly and breaks
what is malbolge
Malbolge () is a public domain esoteric programming language invented by Ben Olmstead in 1998, named after the eighth circle of hell in Dante's Inferno, the Malebolge. It was specifically designed to be almost impossible to use, via a counter-intuitive 'crazy operation', base-three arithmetic, and self-altering code. It builds on the difficulty ...
basically a language designed to be as hellish as possible to use
rust needs while let else
I GOT IT TO WORK
need 200 people to use elle https://github.com/github-linguist/linguist/blob/main/CONTRIBUTING.md
ok well this is weird
when allocating a lot it fails to free most of it
there are quite a lot of leaked arenas
insane
exactly
mfw i made a whole ass interpreter in my first commit to the repo
meh i just privated the old repo and made a new one
thats good
im following something like https://www.conventionalcommits.org/en/v1.0.0-beta.4/
A specification for adding human and machine readable meaning to commit messages
i would have to use this for every commit
xdd
holy shit
omg
it only freed 1 arena
thats why it works for basic examples but not more complex ones
the chunk size for an arena is 64kb
so for a small example it all fit into 1 arena
my pointer indirection for the linked list was wrong
if self.current.used + size > self.current.size {
Arena *arena = Arena::new(self.chunk_size);
arena.next = self.current.next;
self.current.next = arena;
self.current = arena;
}
``` i honestly dont know what i was doing
it should be this
if (self.current.used + size > self.current.size) {
Arena *arena = Arena::new(self.chunk_size);
arena.next = self.current;
self.current = arena;
}
beautiful ast (only supports literals rn)
and now it frees all 700 arenas that were actually created for the day 12 thing
and its very fast too
im gonna struggle with this
good
gonna have to think of the parsing myself cause the syntax is unique, hopefully i wont have to redo my grammar again
insane
finally
i think this leaks report is wrong because it allocated a lot more than 18kb of memory
but i think the reason why it says only 18kb because the bigger allocations were virtual memory
huh i dont see the diff
oh wait it overwrites self.current completely
the OS is actually smart when asking for memory
it reserves virtual memory space but doesnt commit any physical memory until you actually acccess the memory (its called demand paging)
if i do this
for i in 0..1e5 {
#env.allocator.alloc(1024 * 1024);
}
``` it almost allocates nothing on the physical memory even though it should allocate a lot more (it only allocates memory for the arenas themselves not the buffers inside)
but if you go and force the OS to commit the memory
```rs
for i in 0..1e5 {
let ptr = #env.allocator.alloc(1024 * 1024);
// force page commits by writing to the memory
memset(ptr, 1, 1024 * 1024);
}
``` it actually uses all the memory
this behavior is actually really interesting because
- it allows for cheap large allocations as you only commit the memory you use
- it allows efficient over-allocations
In computer operating systems, demand paging (as opposed to anticipatory paging) is a method of virtual memory management. In a system that uses demand paging, the operating system copies a disk page into physical memory only when an attempt is made to access it and that page is not already in memory (i.e., if a page fault occurs). It follows th...
and in the case for my arena allocator its very fast
with arenas
oh wow
its actually even faster than pure malloc
AND it frees all the memory
lol good job
my impl :)
never
oh theres still print statements lol
me when
it's cool that you're now at the stage where you're working on std
lol std has been a thing for a while
yea I know
since about the start of august i think
but i know what you mean
oh btw youre gonna love this
i wrote the entire custom main func in ast
fn main(i32 argc, string *argv) {
let env = ElleEnv {
allocator = ArenaAllocator::new()
};
#env = &env;
#if main_arg_len == 1
let args = Array::with_capacity<string>(argc);
let i = 0;
while i < argc {
args.push(argv[i]);
i += 1;
}
let status = __internal.elle.__main__(args);
#else
let status = __internal.elle.__main__();
#end
env.allocator.free_self();
return status;
}
``` basically this
written by hand in ast nodes
lmfao
you have macros?
no thats pseudocode
oh okay
Btw do you already use the env thing from qbe?
nope not yet
im saving that for closures if i ever implement them
#env is just storing a pointer in static memory
is this enough constants yet
you should refactor it heh
eventually probably
not rewrite, just refactor
we may be getting a longer identifier cap in qbe
yey
refactor it how
put them into a static struct or something
?
not sure but your compiler should be separated into multiple files
maybe idk
oh lol yeah thats something ill do soon
this allocator thing actually doesnt add very much to the compiler itself
okay im gonna implement unary operators
this is my compiler structure rn
compiler.go:
package compiler
import (
"blom/ast"
"blom/compiler/qbe"
)
type Backend int
const (
QBE Backend = iota
LLVM
)
type Compiler struct {
Backend Backend
}
func New(backend Backend) *Compiler {
return &Compiler{Backend: backend}
}
func (c *Compiler) Compile(program *ast.Program) string {
switch c.Backend {
case QBE:
return c.compileQBE(program)
case LLVM:
return c.compileLLVM()
}
panic("Unknown backend")
}
func (c *Compiler) compileQBE(program *ast.Program) string {
qbeCompiler := qbe.New()
qbeCompiler.Compile(program)
return qbeCompiler.Emit()
}
func (c *Compiler) compileLLVM() string {
panic("Not implemented")
}
interesting
and ill do something similar with transpilers
idk im a lot more focused on making progress than design choices even if its unreadable for now
AstNode::Environment { value, location } => {
if let Some(value) = value {
if !self
.data_sections
.iter()
.find(|data| data.name == ENV_ID)
.is_some()
{
self.data_sections.push(Data {
linkage: Linkage::public(),
name: ENV_ID.into(),
align: None,
items: vec![(Type::Long, DataItem::Const(0))],
})
}
let (ty, val) =
self.generate_statement(func, module, *value, ty, None, is_return)
.expect(&location.error(
"Unexpected error when compiling value to set to environment",
));
func.borrow_mut().add_instruction(Instruction::Store(
ty.clone(),
Value::Global(ENV_ID.into()),
val.clone(),
));
Some((ty, val))
} else {
let ty = Type::Pointer(Box::new(Type::Struct(ENV_STRUCT_NAME.into())));
let val = self.new_temporary(None, false);
func.borrow_mut().assign_instruction(
&val,
&ty,
Instruction::Load(ty.clone(), Value::Global(ENV_ID.into())),
);
Some((ty, val))
}
}
``` this thing is silly
and probably ill make same sort of abstraction like i did for qbe for other langs as well
like js, lua, py
you wanna transpile to py??
but first i want working compiler
maybe
and my goal is to make the transpiler actually transpiles into readable code
and not some unreadable nonsense
but compiler is the highest priority rn
Elle to py when?
@valid jetty why you dont have unaryoperation and instead you have everything in literal with tokenkind unary except bitwise not
thats extremely weird
I love the idea of spending time writing good code for it to then be turned into garbage
You can even call it python interop :)
to be honest i dont know
theres a lot of bad decisions in the compiler
well thats parser but yeah
in the.. project?
idk what to call the whole collection of things
the language
the toolchain
the infrastructure
๐ญ
so many modules
ok well all the tests pass
commitey commitey
actually i have to fix the docs
argc and argv arent a thing anymore
hm?
oh actually
i love that args is a string[] now
not only is it iterable but you can use it like any other array
for this:
use std/prelude;
fn main(string[] args) {
let program = args.remove(0);
for arg in args {
if arg == "foo" {
io::dbg("i received a foo!");
}
}
}```
i have this in ast
yeah that looks about right
unary should definitely be just a generalized node
but im silly so
your ast is this
really nice
thats not the updated ellec
theyre called Literal and BinaryOperation but yeah same thing
but you just renamed the names
yeah
yea i have elle cloned so i can easily check QBE :D
uh
assignment is not threated as expression, must fix it
i should implement != lol
the compiler is so much cleaner now
thanks to the qbe abstraction
@valid jetty really thx
wth is wrong with ios jailbrekers ๐ญ
why is there redis server
why would you host redis server on your iphone
xD
whaaa
oh lol i see
okie well i pushed https://github.com/acquitelol/elle/commit/a19d29f3a2371a30979d2db0f1806867db420e09
im sure there are many issues with this
but there are no more memory leaks at last
and its actually faster than it was before
the best part is for most small programs it can manage the whole program runtime in a single 64kb arena lol
this isnt ideal because if the program runs for a while itll still allocate a lot of memory (it only frees at the end) but its at least better than literally leaking it all
and allocation now is way faster if youre allocating often and in small chunks
nah

i must improve my parser and analyzer
then i can work on stuff like that
and probably import system before dynamic memory management
okay if done, while loop next
lool
its because i made changes in AST and used a simple hack in parser instead of actually changing parser
if then, else is not threated as blockstatement anymore but as a list of statements

this is why you should use datetime libraries and not make ur own
or just dont do frontend
let someone else do it
if i ever get a frontend job i have 1 million ideas for how i could keep that job
@valid jetty rosie
friendly reminder that this person used pascalcase for functions (c# hate) https://www.reddit.com/r/redscarepod/comments/10ma10l/im_a_white_man_i_wrote_my_own_compiler/
lmao
@calm ruin arent you a pascalcase user
@calm ruin @calm ruin string methods no longer leak memory
calling string.concat no longer leaks 24 bytes each time
@calm ruin @calm ruin strings exist in the lexer now
whats a lexer
yey
@calm ruin new compiler arrived
lexer sounds so weird to say
i have to use pascal case for global functions in go 
did u finally bother to start freeing
technically it should be called tokenizer if you wanna use the naming convention of tokens
you dont have to use go
otherwise tokens should be called lexemes
bla bla bla
i know but i already wrote 3k lines so im not gonna switch
and go is not a bad language

I am all case user
I use whatever I want
it does lexical analysis of a string and returns it in parser-readable tokens
use UPPER_SNAKE_CASE EVERYWHERE
use rAN-Do__mCAs-_e
and upper snake on static variables
so goood
eh, really it just means you should use iso8601 or a unix timestamp
I think thts cool
icps will enforce a strict no uppercase letters policy
no i wrote a whole arena allocator and setup an env system where a pointer to an env struct is stored in static memory then allocations all go through the arena allocator instead of malloc and are freed at the end (#env.allocator.alloc is abstracted from the developer, they just use it, its up to the compiler to determine which allocator structure to put into #env.allocator)
thats literally the whole point of what ive been talking about for the past 2 days lol
basically just don't store dates like americans
idk what an arena is
a region of memory
basically allocate things in chunks
i still hate windows that it stores time in specific timezone instead utc
malloc(10239120391);
so you cant have different timezones on different accounts lol
u cant tell ur users that the current time is 1798346187
/run
int main() {
int *e = malloc(123912381223323);
*e = "aagaming";
printf("%s", e);
}
@calm ruin I received c(10.2.0) compile errors
file0.code.c: In function 'main':
file0.code.c:2:10: warning: implicit declaration of function 'malloc' [-Wimplicit-function-declaration]
2 | int *e = malloc(123912381223323);
| ^~~~~~
file0.code.c:2:10: warning: incompatible implicit declaration of built-in function 'malloc'
file0.code.c:1:1: note: include '<stdlib.h>' or provide a declaration of 'malloc'
+++ |+#include <stdlib.h>
1 | int main() {
file0.code.c:3:4: warning: assignment to 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
3 | *e = "aagaming";
| ^
file0.code.c:4:1: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
4 | printf("%s", e);
| ^~~~~~
file0.code.c:4:1: warning: incompatible implicit declaration of built-in function 'printf'
file0.code.c:1:1: note: include '<stdio.h>' or provide a declaration of 'printf'
+++ |+#include <stdio.h>
1 | int main() {
/piston/packages/gcc/10.2.0/run: line 6: 593183 Segmentation fault (core dumped) ./a.out "$@"
why not
they probably just use date objects
maybe they were reading incorrectly from the user
if you wanna allocate a bunch of 4 byte structs theres no point to do a seperate dynamic allocation for each one (thats slow), just allocate one big region of 64kb (the current size of an arena) and store it all in there
if allocating something exceeds the size of an arena just create a new arena and keep them all linked via a linked list
which also makes it very easy to free all the memory at the end because you just free all the arenas in the linked list chain
american instead of normal
which fails to parse bc of different regions
they should have just used one of the two standards
segfault 
wont that be really inefficient if my rocks multiply when i blink and i need the middle rock after 65536 blinks
and this is abstracted from the user so i can easily swap it out to something else like a bump allocator or garbage collected allocator or direct heap allocator you just switch what structure is put into #env.allocator in the compiler
@valid jetty add function to elle which is randomem, it will return random memory adress for you to write
youre misunderstanding i think
oh
so you can nuke your program accidently
Pointers still exist
you don't need to check the entire region every time
sorry i forgot that elle is a low level language
something like this
struct Foo {
void *a;
void *b;
void *c;
void *d;
};
fn Foo::new() {
Foo *foo = #env.allocator.alloc(#size(Foo *));
*foo = #env.allocator.alloc(#size(Foo));
foo.a = foo.b = foo.c = 0;
return foo;
}
for i in 0..100 {
let foo = Foo::new();
io::dbg(foo);
}
i thought u needed to traverse each chunk
if #env.allocator.alloc is set to just called malloc each time, thats really slow
instead its set to just give you a chunk out of a 64kb page of the size you request
if there isnt enough space left it makes a new 64kb region and gives you memory from that
and then links it to the old one with a linked list
you never search anything because you just hold a pointer
the only time you would ever need to search the linked list is for a freelist realloc thing but i didnt implement that, realloc just allocates new memory and copies the buffer into it
oh i thought it allocated >= 64kb for every struct
no lol
its like a pool
everything is allocated into the 64kb
at the end you just traverse the linked list of arenas and free each one
ur just preallocating 64kb
not exactly
if you need more than 64kb it allocates another 64kb and links them together
and then you have another 64kb preallocated
if the memory allocation you want is more than 64kb (the size of an arena) it makes a custom arena with specifically that size youre requesting (aligned to 8 bytes)
yes and then it keeps doing that for the whole program runtime
for example my day 12 solution allocates 812 arenas iirc
that sounds awesome
good thing im not gonna have to do it any time soon
ideally this thing would be linked to a garbage collector to free allocations that arent used anymore
whens the elle borrow checker update dropping
borrow checking sounds so easy on paper but so hard to actually write
it sounds hard on paper
you need to know so many intrinsics about a program at compile time
rust has the MIR (pre-ir) for analyzing and enforcing borrow checking rules lol
theres this if you wanna mess with it https://github.com/rust-lang/miri
you might have to do it never if you never write a compiler lol
man i really hope the performance of the interpreter will be bearable so i dont have to do any of this shit
you dont really need to do any of this
you can get away with literally leaking all dynamic memory with malloc
the system will go and release it when a program finishes execution anyway
i did that for the longest time and it worked fine
ah yes the pretend garbage collector
man tsoding is not real
when i first heard of him i thought it was a misspelling of tscoding and didnt check who he was cause i thought hes another ts codefluencer
would you rather
for x in [39, 40, 41] {
io::dbg(x);
}
or
let arr = [39, 40, 41];
defer arr.free();
for x in arr {
let str = io::dbg(x);
mem::free(str);
}
bro did aoc 2021 visualizations in fucking holyc
Reference:
- Advent of Code in TempleOS: https://www.youtube.com/playlist?list=PLpM-Dvs8t0VZNUvTX1pqfpI_tMkhWCLYL
- Advent of Code: https://adventofcode.com/
- TempleOS: https://templeos.org/
- Source Code: https://gitlab.com/tsoding/aoc-2021
and its so much easier than opengl
idk but this stream was so cool https://www.youtube.com/watch?v=JaG4kdyS_I8
Streamed Live on Twitch: https://twitch.tv/tsoding
Enable Subtitles for Twitch Chat
More Episodes: https://www.youtube.com/playlist?list=PLpM-Dvs8t0VaTz0wuDbwMfilC_JZkZKK5
Wallpapers: https://penger.city/wallpapers/
References:
gn
i love him romantically
wtf
its only 11pm
how are you maintaining a sane sleep schedule during a holiday
i literally stayed up to 6am last night
i was sleeping at 6:30pm during aoc
