beneroth changed the topic of #picolisp to: PicoLisp language | The scalpel of software development | Channel Log: https://libera.irclog.whitequark.org/picolisp | Check www.picolisp.com for more information
f[x] has joined #picolisp
f[x] has quit [Remote host closed the connection]
_whitelogger has joined #picolisp
geri` has joined #picolisp
<geri`> hey-hey
<geri`> i made a as-simple-as-possible-while-still-RFC8259-compliant edition of my json parser: https://0x0.st/X5sZ.l
<geri`> :D
<geri`> this version is very much garbage in garbage out though
<geri`> but ~100 less lines
<abu[7]> ok ;)
<geri`> if you see some place that may have performance issues do tell me
<abu[7]> T
<geri`> i also read in the standard that parsers always need to be able to parse proper inputs but they may parse invalid/non-json forms too
<abu[7]> The backslash in json-read-\u-digits is lost
<geri`> its consumed by json-read-escape-code
<geri`> i didnt know how else to organize
<abu[7]> I mean, it is lost in the pil reader
<abu[7]> : 'json-read-\u-digits
<geri`> oh
<geri`> haha
<abu[7]> "u" is quoted
<geri`> okay
<geri`> ill either rename or inline
<abu[7]> no issue anyway
<geri`> i ran some tests i found on a github repo and it seems that (char) just ignores 0 byte
<abu[7]> Yes, not only 'char'
<geri`> eh
<abu[7]> Symbol names cannot contain a null byte
<abu[7]> (like in C)
<geri`> so theres like no workarounds for this
<geri`> langauge level thing
<abu[7]> T
<geri`> language*
<geri`> eh
<abu[7]> (rd 0) can read it
<geri`> but still cant represent it as anything but a number
<geri`> which would hurt
<geri`> so strings would need to be lists of characters instead
<geri`> xd
<geri`> i wont bother
<abu[7]> a list of numbers
<geri`> s/characters/character codes/
<geri`> yes
<abu[7]> Your code looks very good
<geri`> thank you 🙏
<abu[7]> ☺
<abu[7]> (lintAll) does not complain :)
<geri`> aw yeah
<geri`> i also just treat : and , as whitespace cause its not technically forbidden
<geri`> :D
<geri`> makes object/array reading so much simpler
<geri`> printing should still be valid though to be conformant, so it is the way it is
<abu[7]> I see
<geri`> well, its valid for valid inputs
<geri`> :D
<geri`> but overall translation to and from json is good and im happy about it
<abu[7]> 👍
rob_w has joined #picolisp
rob_w_ has joined #picolisp
geri` has quit [Ping timeout: 276 seconds]
theruran has quit [Quit: Connection closed for inactivity]
geri has joined #picolisp
<geri> i should stop forgetting to plug my pc in xd
<abu[7]> What exactly happened? You forgot to plug in the power supply?
<abu[7]> ie a notebook?
<geri> yeah, a laptop
<geri> i dont have enough power sockets for a lamp, router, monitor and 2 pc's
<geri> so when its dark im alternating between the two and i keep on forgetting to xd
<geri> what's a difference between a property list and an alist, other than having slightly different cons cell structure?
<abu[7]> None. Plist is a 'rasoq' list. Perhaps the CDR of the last cell, which is a number, but this is ok for an assoc-list too
<geri> wdym by a rasoq list? something about reverse asoq function :thinking:
<abu[7]> Yes
geri2 has joined #picolisp
<abu[7]> There is also 'rassoc'
geri2` has joined #picolisp
<geri2`> like you need to use rassq to get a value out of plist?
<abu[7]> out of such a "reversed" plist
geri2 has quit [Ping timeout: 276 seconds]
geri2` has quit [Read error: Connection reset by peer]
geri2` has joined #picolisp
geri2` has quit [Remote host closed the connection]
geri2` has joined #picolisp
geri2` has quit [Read error: Connection reset by peer]
<geri> there's so many of me!
<geri> got simple examples of doing OOP?
<geri> im kinda lost with variables and instantiating stuff
<geri> read on (doc) that classes arent really different from objects and thats about all i know :D
<geri> and managed to run dm with a (class) i just created
<abu[7]> There is the tutorial
<geri> tut.html?
<geri> or somewhere on wiki
<abu[7]> yes
<tankf33der> no OOP :)
<abu[7]> oh
<tankf33der> there is my copy of old tut.html
<abu[7]> This used to be in the release, but was put separate
<abu[7]> Because it needs source files which bloat the release
<geri> makes sense id guess
<abu[7]> demo sources
<abu[7]> beneroth wrote up some stuff about pil OOP
<abu[7]> Can't find it atm
<geri> aw
<geri> maybe when he's here he'll link it
<abu[7]> yeah
<geri> cant find what (dm T ...) means in docs
<geri> guessing its like init method
<geri> constructor
<abu[7]> Yes, an init
<abu[7]> see 'new'
<geri> ah great
<abu[7]> "the initial T message is sent"
<geri> how'4 performance of methods compared to functions?
<abu[7]> A little slower, depending how many (super)classes are searched
<geri> oh wait uh
<geri> so i can have a symbol storing a function also store values inside using its list?
<geri> xd
<abu[7]> plist?
<geri> its plist*
<geri> yes
<abu[7]> T
<geri> thats funny
<abu[7]> The value of a symbol is just a special, efficient property
<geri> true
<geri> when you run dm, what's the pointer in the symbol's value to?
<geri> i thought you cant create arbitrary functions in C at runtime
<geri> (well, its llvm now but still)
<abu[7]> messages all point to the same code
<abu[7]> 'meth'
<geri> oh
<geri> so its just syntactic sugar?
<abu[7]> no
<geri> vs just (send 'method-name Object . Args)
<abu[7]> 'meth' searches for the symbol whose value it is
<abu[7]> in the oop hierarchy
<abu[7]> Yes, (send 'method-name is equivalent
<abu[7]> brb
<geri> oki
corecheckno has quit [Remote host closed the connection]
<abu[7]> ret
<geri> herro
<geri> and the sun is down again
<abu[7]> here not yet
<abu[7]> in 1 h 20 min
<geri> well, technically not here either, but its so cloudy it looks like it
<abu[7]> ah
<geri> had to unplug one of pc's for the lamp
<abu[7]> :D
<geri> lets hope i wont forget to re-plug it again
<geri> xd
<abu[7]> you'll learn :)
<geri> yeah, i believe in my ability to learn
<geri> B)
rob_w_ has quit [Ping timeout: 248 seconds]
bjorkintosh has joined #picolisp
bjorkintosh has joined #picolisp
<geri> if i need to share a single list across many functions and flow is not trivial (a bunch of recursion), is it better to use some sort of global variable or using dm and classes?
<geri> and object variables
<abu[7]> I would first try global. OOP is for inheritance and polymorphism
<geri> and encapsulation!
<abu[7]> yep
<geri> if i mark a symbol as (local), will it still be visible for a function from the same file after loading the file?
<abu[7]> "visible for a function" is not the right term, (local) and namespaces are relevant for reading only
<abu[7]> functions will refer to it
<geri> will it be visible in pico namespace?
<abu[7]> Not if it is local in another namespace
<geri> eh
<abu[7]> It will be found by 'read' only if that namespace is in the search order
<geri> hm
<abu[7]> (symbols '(foo pico))
<geri> have you ever seen pico namespace not being used?
<geri> intentionally
<abu[7]> What do you mean wpth "used" here?
<abu[7]> *with
<geri> disabled namespace, just some personal one instead
<geri> actually doesn't matter
<geri> i dont think i can put my json reader into its own namespace cause it uses == against some symbols
<abu[7]> Namespaces are relatively new in pil
<abu[7]> This should be ok
<abu[7]> a common case
<abu[7]> If Json is used, the search order will include it
<geri> okay
<geri> then if ill hate the fact tokens are exposed in a global variable ill go to namespaces :D
<abu[7]> This == is also for all property accesses
<abu[7]> In PilBox, each App must be in its own namespace
<abu[7]> as they all run in the same process
<geri> trying to see if ill be able to make the "proper" json parser simpler by doing tokenizing first
<abu[7]> ok
<geri> abu[7]: must they be or it's better to
<geri> cause collissions
<abu[7]> ok, just better
<abu[7]> right
<abu[7]> especially DB models
<abu[7]> many apps have a DB
<geri> shouldnt symbol lookup also be slightly faster in separate namespaces?
<geri> cause need to look through less stuff
<abu[7]> Possibly
<abu[7]> though searching many spaces also takes time
<geri> yeah..
<abu[7]> In some apps I have many namespaces
<abu[7]> messe: (namespaces T)
<abu[7]> messe
<abu[7]> leg
<abu[7]> svg
<abu[7]> pico
<abu[7]> vip
<abu[7]> llvm
<abu[7]> priv
<abu[7]> -> (messe leg svg pico vip llvm priv)
<abu[7]> messe and leg are from the application
<abu[7]> the rest is loaded
corecheckno has joined #picolisp
<abu[7]> Same in PilBox:
<abu[7]> messe: (namespaces T)
<abu[7]> messe
<abu[7]> leg
<abu[7]> svg
<abu[7]> android
<abu[7]> pico
<abu[7]> vip
<abu[7]> gis
<abu[7]> llvm
<abu[7]> demo
<abu[7]> priv
<abu[7]> simul
<abu[7]> steps
<abu[7]> chess
<abu[7]> scrawl
<abu[7]> kegeln
<abu[7]> wecker
<abu[7]> browser
<abu[7]> battery
<abu[7]> barometer
<abu[7]> -> (messe leg svg android pico vip gis llvm demo priv simul steps chess scrawl kegeln wecker browser battery barometer)
<abu[7]> messe:
<abu[7]> (after 🣬icking on several apps in PilBox)
<abu[7]> Hmm, indentation is lost in stupid IRC
<geri> sad
<geri> that's a lot of libraries!
<geri> well, namespaces*
<abu[7]> T
<geri> also i just realized i dont even need a global variable, i can just (use Tokens) in entrypoint function
<geri> :D
<geri> forgot about dynamic binding
<abu[7]> gives free variable in sub-functions
<geri> yeah
<abu[7]> you can still call it *Token
<geri> not the best, but those are internal functions and normally will never be called outside of the entrypoint
<abu[7]> to keep lint happy
<geri> (use *Tokens ...) ?
<abu[7]> T
<geri> fair
<abu[7]> otherwise subfuns should be _foo
<geri> _ for internal function?
<abu[7]> or do (noLint 'foo 'Token) or so
<abu[7]> yes
<geri> aha
<geri> i should do it
<abu[7]> That's best
<abu[7]> I often use noLint
<geri> _json-skip-whitespace looks kinda ugly honestly
<abu[7]> yeah
<abu[7]> I avoid usually
<abu[7]> IIRC a private function is also not complained about
<abu[7]> (private) json-skip-whitespace
<geri> what's the difference between private and local
<abu[7]> 'priv' is a built-in special namespace
<abu[7]> It is always searched first, but never interned to automotically
<abu[7]> You can 'private' a symbol multiple times in a file and get a new symbol each time
<geri> does only that one symbol get interned in priv?
<geri> and everything else in whatever current namespace is
<geri> like, if i do (private) json-skip-whitespace and in its body i have 'hello
<geri> where's that hello interned
<abu[7]> in the current normal namespace
<geri> okay good
<geri> then private is probably a good solution
<geri> (private) (SYM1 sym2) for many?
<abu[7]> Yes
<geri> how do you format many private symbols?
<geri> (hello
<geri> world
<geri> test)
<geri> ?
<abu[7]> I make a single line
<abu[7]> without indent
<abu[7]> just wrap
<abu[7]> Not beautiful ;)
<geri> very not beautiful
<abu[7]> Your example above would be more consistent
<abu[7]> But gets very large
<geri> yeah...
<geri> tough
<abu[7]> see eg. @lib/vip.l
<geri> we need a reverse private
<geri> everything is private until you say otherwise
<abu[7]> This would break the Lisp reader logic
<abu[7]> Intern new symbols if the reader does not find them
<geri> ;-;
<abu[7]> Transients are poon man's private syms
<abu[7]> No namespaces at that time
<geri> so (de "json-skip-whitespace" ...)?
<abu[7]> T
<abu[7]> ugly
<abu[7]> Sorry, must stop
<geri> xd
<abu[7]> Kids and grandkids visited
<geri> ah
<geri> have fun!
<abu[7]> Later :)
<abu[7]> Thanks!
corecheckno has quit [Remote host closed the connection]
corecheckno has joined #picolisp
<geri> silly idea - you could define a function like (de func . body) and call it inline with (~func) to use it as a "macro"/inline without a function call
<geri> if it takes no arguments anyway
<abu[7]> T
<abu[7]> But it is not faster
<geri> ~ is slow?
<abu[7]> Exactly the same
<geri> wouldnt it be faster if you do the tiny function call a lot
<geri> its only read once
<abu[7]> Then (run '`(cdr fun))
<abu[7]> This avoids a funcall
<abu[7]> just the bodg
<abu[7]> body
<geri> and its still usable as a standalone function
<abu[7]> T
<abu[7]> (fun) just gets the value and calls at a function
<abu[7]> The in
<abu[7]> line takes the CAR
<abu[7]> and calls at a function
<abu[7]> So it is the same
<abu[7]> (run '`(cdr fun)) avoids the evExpr() overhead
<abu[7]> bind the (non-existent) arguments
<geri> and could wrap it in another read macro if verbose
<geri> xd
<geri> fun
<geri> (~func) looks so nice though
<abu[7]> But just (func) looks even nicer ;)
<geri> but slower
<abu[7]> No
<abu[7]> perhaps faster
<geri> 🤔
<abu[7]> evList() first tries for symbol
<geri> so if list is a single symbol itll skip all other stuff?
<geri> s/is/has only/
<abu[7]> Which list?
<geri> (func)
<geri> other stuff == binding nonexistent arguments
<abu[7]> (run '`(cdr fun)) would skip it
<abu[7]> But the code gets bigger
<abu[7]> more gc
<geri> and more obfuscated
<abu[7]> worse cache
<abu[7]> yes
<abu[7]> I think the differences in speed for all 3 versions are not measurable
<geri> cant just call the functions in a loop?
<abu[7]> Interpreting the body of fun takes time
<abu[7]> Which functions?
<abu[7]> (bench 999999 (... (func) )) ?
<geri> (de fun () (prinl "Hi"))
<geri> (bench (do 10000 (fun)))
<geri> (bench (do 10000 (~(cdr fun))))
<geri> (bench (do 10000 (run '`(cdr fun))))
<abu[7]> T
<geri> second one broken
<abu[7]> Thought so
<abu[7]> needs a quote
<geri> no wait
<abu[7]> ('(~fun)) ?
<abu[7]> or ~(cdr fun)
<geri> (de fun2 . (prinl "Hi")) (bench (do 10000 (~fun2)))
<geri> but again, fun2 is not usable in standalone mode then
<geri> honestly not sure about timing, its kinda all over the place on my machine
<abu[7]> (de fun2 . (prinl "Hi")) is not useful
<abu[7]> binds 'prinl'
<abu[7]> and returns "Hi"
<abu[7]> same as (de fun2 prinl "Hi")
<geri> yeah its not a function
<geri> its a snippet
<abu[7]> ah, ok
<geri> sec, let me try in xterm
<abu[7]> so ~(cdr fun) is perhapt the best
<abu[7]> Splices the body
<abu[7]> 'run' is not needed
<geri> yeah probably
<geri> 1 less function call too
<geri> even if its a builtin
<geri> it still runs all over the place
<geri> ~ seems to be only slightly in front of other two
<geri> like 0.010s difference for 100000 runs
<abu[7]> Must be ~(copy (cdr fun)) though
<abu[7]> ~ is destructive
<abu[7]> Othervise fun is concatenated
<geri> i ran the thing many times without copy and fun is the same
<geri> hmm
<geri> or you mean if you change fun
<abu[7]> No
<abu[7]> fun is modified if you do (a ~(cdr fun) b c))
<abu[7]> (b c) is concatenaded to fun
<geri> oh
<geri> :(
<geri> no stylish function calls, very sad
<geri> macro calls*
<abu[7]> You need just to copy
<abu[7]> : (de f () (a))
<abu[7]> -> f
<abu[7]> : f
<abu[7]> -> (NIL (a))
<abu[7]> : (1 ~(cdr f) 2 3)
<abu[7]> -> (1 (a) 2 3)
<abu[7]> : f
<abu[7]> -> (NIL (a) 2 3)
<geri> yeah ive seen it
<geri> i dont like that inlining code has to be ugly
<abu[7]> true
<geri> i really like (case X (`(chop "a bunch of symbols")))
<geri> very meta
<abu[7]> T
<geri> honestly separate lexer and parser for json feel kinda nastier
<geri> i guess you need enough complexity to justify that or something
<geri> i even got a nice state machine for lexing exactly one value
<geri> *only 39 lines*
<geri> xd
<abu[7]> With the 'state' function?
<geri> nah, just a loop with (case)
<geri> maybe should try state
<abu[7]> ok
<geri> is that kinda like gotos?
<abu[7]> Not really
<geri> well, its kinda horrifying honestly
<abu[7]> T
<geri> i wanted to try a lexer/parser combo for my lisp in python and just figured it felt simpler when reading char by char directly
<geri> and like 60% of the code compared to lexer and parser
<geri> xd
<geri> well, ive learned how utf-16 and json work while writing the json parser, worth it :D
<abu[7]> 'vip~markup' uses a rather similar state machine I think
<abu[7]> States like text, string, skip, comment
<geri> and as scary looking
<geri> :D
<abu[7]> yep :)
<geri> my terminal window tends to be 30 lines high, if i need to scroll to see what a function does it feels nasty
<geri> long functions in forth are another level of awful entirely
<abu[7]> In Forth you get lost quickly
<geri> yeah
<geri> idr if i told you but i wrote a good chunk of lisp interpreter's core in forth
<geri> mostly on my phone too :D
<abu[7]> Nice!
<geri> doing a tiny interpreter in C really made me appreciate pushing bits
<geri> ...around
<geri> bit tagging and everything too
theruran has joined #picolisp
<geri> abu[7]: what should i do about error handling in json-read?
<geri> rn im catching whatever string i throw, but its kinda weird that it returns a string when failing
<geri> and may be confused for a success because of that honestly
<abu[7]> I do (msg @@) after an error catch
<geri> like (de func () (catch 'tag ...) (msg @@))?
<geri> for some reason it returns T for me
<abu[7]> I use *Msg
<abu[7]> @@ is T, right
<abu[7]> (catch '("Exception") ..) (and @@ (msg *Msg))
<geri> and now read always returns NIL
<geri> xd
<abu[7]> hihi
<geri> oh wait a sec
<geri> nah it does return nil
<geri> i thought it was a problem that i called a wrapper instead
<geri> im honestly pretty happy with the design, even if its very relaxed
<abu[7]> good :)
<geri> what's @@ set to when catch gets triggered?
<geri> T if error NIL if all is fine
<geri> nvm xd
<abu[7]> T or NIL
<abu[7]> yep
<abu[7]> T if thrown
<geri> it would be kinda weird for a function to return T when it failed
<geri> but NIL represents an empty string so its ambigious
<geri> xd
<abu[7]> T means yes, it was thrown, o non-local exit
<abu[7]> s/o/a
<geri> yeah i mean my read function
<geri> it cant return nil cause its either "i broke" or "i read you a string"
<geri> empty string
<geri> returning T is more consistent cause its never used otherwise, but weird
<abu[7]> Better handle the throw separately, not via return value
<geri> like don't catch it?
<geri> whoever's calling the lib catches it instead
<abu[7]> Hard to say
<geri> could just return 'broken
<abu[7]> Best is simply to 'quit' and not throw at all
<geri> hm
<abu[7]> The user of the lib may catch if needed
<abu[7]> Depends if the errors are fatal or not
<geri> all reader errors are fatal
<abu[7]> Good
<geri> how do you catch quit
<abu[7]> Then just 'quit'
<geri> with (catch) too?
<abu[7]> (catch '("foo" "bar") ...
<abu[7]> (catch '("not found") ...
<abu[7]> see bluetooth above
<abu[7]> catches simply "Exception"
<abu[7]> ie all
<geri> if i have (throw 'json-error (pack "Wrong escape: '" @ "'")), how do i make it into quit?
<geri> kinda confused about the args
<abu[7]> (quit _Json Error")
<abu[7]> (quit "Json Error")
<geri> okay
<geri> thankfully the change is like 1 line
<geri> cause got a helper
<geri> :D
<abu[7]> :)
<geri> is it normal that catching it still changes the prompt to "? "
<abu[7]> No, it is not caught then
<abu[7]> string mismatch?
<geri> even if i do (catch T) its not caught
<abu[7]> right
<geri> okay wait
<geri> now it worked
<abu[7]> this catchs throws
<abu[7]> (catch '(NIL)
<abu[7]> catches all errors
<abu[7]> ie (catch '("")
<geri> (catch '("Json Error") (json-read-from-string "{"))
<geri> Unexpected EOF while reading a JSON value
<geri> -> "Json Error"
<geri> good?
<geri> just printed the error message i had
<abu[7]> Yay
<abu[7]> it is returned
<geri> i love how you dont need to create classes and stuff for exceptions
<geri> just return a string, that's it
<abu[7]> T
<geri> (catch '("J") (json-read-from-string "{")))
<geri> i like how this still works
<geri> is there any convention for capitalization in throw/quit tags
<geri> seems to just be a capitalized sentence minus punctuation
<abu[7]> There is no rules - many erron messager home from the system
<geri> oki
<geri> (de json-read . `json-read1)
<geri> is this acceptable :D
<abu[7]> Yes, I have such cases too
<geri> could rename read1 to be read but then its hard to find entrypoint functions
<abu[7]> often in methods
<geri> okay neat
<geri> i added a ton of text in the beginning and my code is actually smaller than before
<geri> feels very nice
<geri> and more functional too
<abu[7]> (dm methX> ~(method 'methX> '+Cls))
<abu[7]> get a meth from another class
<geri> neat
<geri> theres so many tools that make code shorter, kinda insane
<abu[7]> indeed :)
<geri> what do you think about trying to handle every error case in code?
<abu[7]> hmm, depends
<abu[7]> I prefer to handle it lazily
<abu[7]> defer to top level
<geri> like offloading to user? :D
<abu[7]> In production apps I pop a dialog ;)
<geri> haha
<abu[7]> or log it and exit
<abu[7]> Applications load @lib/app.l
<abu[7]> (de *Err ...
<abu[7]> then exits the process
<abu[7]> Exit is a feature of Pil if no TTY
<geri> and then the app is down 😭
<abu[7]> No, just this child
<geri> poor child
<abu[7]> The server process continues
<abu[7]> T
<geri> now its 153 loc of actual code
<geri> amazing
<abu[7]> Exit is important, so that no inconsistant data are committed to the DB
<abu[7]> 👍
<geri> yeah, db + garbage data == craving death
<geri> garbage data is overall pretty painful
<abu[7]> right
<geri> aighty gotta sleep
<geri> night night
<abu[7]> Bye!
geri has quit [Quit: ERC 5.5.0.29.1 (IRC client for GNU Emacs 29.4)]
z4k4ri4 has quit [Ping timeout: 245 seconds]
z4k4ri4 has joined #picolisp
corecheckno has quit [Remote host closed the connection]
rob_w has quit [Read error: Connection reset by peer]
corecheckno has joined #picolisp
corecheckno has quit [Remote host closed the connection]