libera/commonlisp - IRC Chatlog
Search
1:26:23
Guest74
getting closer I think. Pretty sure the diagonals are indicative of some error on my part. https://youtu.be/W0-eUFMgJ-o
2:24:21
Spawns_Carpet[m]
do you guys think the lexer should be responsible for handling escapes in strings in source code?
2:48:46
Alfr
Spawns_Carpet[m], that's a strange question to ask for common lisp; reading strings is done using a reader macro function associated with " . see ^
2:51:32
hayley
The Common Lisp specification states that you read forms with a simple dispatch technique, rather than a lexer and parser. I'm aware that fancier readers, such as Eclector, are more sophisticated, but I don't know if they lex and parse.
2:55:48
Alfr
hayley, if you consider the turning streams of characters into tokens, in some sense read does that, though you immediately get the denoted objects. (But 2.2 talks about accumulating tokens.)
2:56:52
hayley
Right, I guess there is a concept of a "token", but it is usually consumed immediately, and there is no separation between reading tokens, and producing nested structure from tokens.
3:32:16
Spawns_Carpet[m]
i am scanning and building up tokens and then linking those together in an SExpr data structure in rust which is a struct with car, cdr, both being an SExpr Value which is a tagged union of Symbol, String, Int, Char and SExpr which contains the next SExpr like a linked list
3:34:57
Spawns_Carpet[m]
what do you mean by that? I have another LispValue union that contains 'compiled' lisp values later on
3:35:37
hayley
A lexer, at least to me, scans over an entire file or string or something, and produces a sequence of tokens, which a parser then consumes in another pass.
3:39:12
Spawns_Carpet[m]
my line of thinking was that the bytecode compiler should work on an AST, and in lisp the AST is an sexpr, so thats what I was parsing and feeding into the compiler, then the compiler emits the actual lisp objects for the interpreter to work with
3:41:59
hayley
Well, okay, but it seems weird to call the same objects both an "sexpr" and "lisp objects", and I am wondering if there is something I've missed.
3:43:23
hayley
Say, we have some code (F 'X). Presumably the whole list won't appear in bytecode, but the symbol X will.
3:45:55
Spawns_Carpet[m]
right, it would do something like EVAL(F), PUSH_SYMBOL(X), CALL 1 is my guess
3:47:42
hayley
What does the EVAL instruction do? It would be...odd for the bytecode VM to have an instruction which does a plain EVAL.
3:47:53
Spawns_Carpet[m]
in this case eval would load a lisp object from the environment and put it on the stack
3:48:31
pillton
Spawns_Carpet[m]: You might enjoy the book Lisp in Small Pieces by Christian Queinnec.
3:49:17
hayley
The one bytecode VM I did turned everything into De Brujin indices, i.e. every local variable and constant had a number. Then I might emit GET-ENV 0; GET-CONSTANT 0; TAIL-CALL 1;
3:49:19
Bike
i would think that you'd have like PUSH_SYMBOL(F) LOOKUPF or something, meaning look up the global function named F
3:51:26
Spawns_Carpet[m]
that probably makes more sense yeah, especially since everything at the start should be a function
3:52:08
Spawns_Carpet[m]
*no-defun-allowed*: that sounds really cool, I've never heard of that before
4:04:10
hayley
Depending on how you handle the environment, especially if functions and other bindings reside in the same "namespace" or not, having a LOOKUP-FUNCTION that is different to LOOKUP-VALUE may or may not make sense. Because this is #commonlisp I am legally obligated to assume you have separate namespaces, of course.
4:12:51
Spawns_Carpet[m]
haha, yeah I was planning on keeping one namespace for functions and variables but I am not super dedicated to either method
4:15:23
spiaggia
Spawns_Carpet[m]: The difficult part of a Lisp system is the evaluator. You can save yourself a lot of trouble if you write your system in Common Lisp, and use the host READ to parse your code. Then you can concentrate on the hard part.
4:19:52
spiaggia
Spawns_Carpet[m]: Sure. It is very hard to give you advice if you are implementing "a Lisp" that is not one that has a specification. Then anything you do is obviously "right" because that's how you have decided that things work in this Lisp.
4:20:46
spiaggia
Spawns_Carpet[m]: The best we can do is to tell you how the Common Lisp HyperSpec says that things must be done, since this is #commonlisp, after all.
4:21:26
Spawns_Carpet[m]
i am having trouble trying to figure out with the reader algo is an actual concrete idea of what the reader should return in terms of rust data structures
4:22:16
Bike
you should probably just have it return lisp-manipulable objects. whatever that means in your system.
4:22:40
spiaggia
Spawns_Carpet[m]: Most code elements in Common Lisp would result in lists in the form of CONS cells, and atoms such as symbols and numbers.
4:22:44
Bike
as hayley said, a READ function is often exposed to the lisp, and that's what you're implementing. since it's a function lisp can call, it should return a lisp object.
4:23:44
Spawns_Carpet[m]
okay that makes a lot of sense when you say it like Bike, i know exactly what you mean now. I actually debated for a while whether it should return the actual internal representation of lisp data types or not, and asked around elsewhere and some people said to not do it, and others said to do it
4:25:46
Bike
also, even if you don't expose READ, you will presumably have an EVAL function that takes a lisp object and evaluates it into another object, and you'll want to pass the result of your parse to EVAL, so
4:26:46
hayley
I mean, it can help to have some other representation with source tracking information, so that any compile-time errors (for example) can reference where the error is in a file, but that is more complicated, and I don't know what they were thinking of instead.
4:28:12
hayley
Okay then. But it is more effort, and I wouldn't bother for my first (few) interpreter(s).
4:29:11
Spawns_Carpet[m]
to be clear also, the bytecode compiler should be processing the actual lisp objects themselves and not the AST-like thing
4:29:35
Spawns_Carpet[m]
since the lisp objects pretty much are the source code I guess that makes sense
4:30:07
Alfr
Spawns_Carpet[m], one thing nice in most(?) lisps is that read returns a tree made of conses, that those conses are also directly manipulable using functions in lisp and certain (valid for the language in question) trees can be passed to eval to be treated as code and executed. Also those trees usually are more or less AST you asked for above.
4:34:17
Spawns_Carpet[m]
the good thing is that it will be super easy to change the reader to emit actual lisp objects. My "AST" data structure actually was pretty much exactly how I represented the lisp objects anyways, except it had a different name
4:41:26
Spawns_Carpet[m]
what happens when the reader has to read multiple top level lists by the way? should I wrap the entire program in an invisible progn?
4:43:17
Bike
usually a file loader will call READ repeatedly, advancing the input stream/port/whatever you call it as it goes
5:02:24
Spawns_Carpet[m]
is the interpreters representation of lisp objects always going to have to be the same as the lisp objects emitted from the reader? that is the idea right
5:03:28
Spawns_Carpet[m]
that is strange that the compiler uses the same structure that the interpreter uses, but also really cool
5:04:34
hayley
As a rule of thumb, the compiler definitely does not use the list-and-symbol-based representation of Lisp code.
5:05:22
hayley
The reader produces a form that can be interpreted, but the compiler usually converts this form into another representation more suitable for analysis.
5:12:51
spiaggia
Though, a very simple compiler for a very simple language could probably generate code directly from the S-expression representation of the program.
5:13:14
spiaggia
It would have the same structure as the evaluator, but instead of computing a value, it would emit code to compute that value.
5:15:53
spiaggia
Spawns_Carpet[m]: What hayley is referring to is that most serious compilers for serious languages do a lot of optimizations to the code, and those optimizations typically require some intermediate representation that is neither the S-expressions nor the final instructions (bytecode or native).
5:17:42
Spawns_Carpet[m]
yeah I am not worried about that right now, needing an IR would be a good problem because that means your language it advanced enough and working well enough to benefit from optimizations !
5:19:38
spiaggia
Spawns_Carpet[m]: So maybe you need to think about your long-term goals with this thing. Those goals could determine how much you need to learn about compiler design and what data structures to choose.
7:14:34
spiaggia
jackdaniel: I'll be back on #clim tomorrow or Saturday I hope. This dinky laptop does not encourage participation is very many IRC channels.
7:52:30
lukego
Hey does anyone happen to know why cffi on #+unix tries to load libffi.so.7, libffi.so.6, libffi.so.5? Can't it just use libffi.so? I ask because I need to support libffi.so.8 and it feels a bit cargo-cult to add that as the next special case. This tradition seems to go back at least a decade.
8:19:03
jackdaniel
http://lispcaveats.tumblr.com/post/13259176455/ffi-linking-against-shared-libraries.
8:20:16
hayley
Apparently that post doesn't exist, nor does the blog. Thus there are no Lisp caveats!
8:26:05
lukego
"the" commit message? I went spelunking with 'git log -S libffi' and so on and turned up lots of commits but not a reason
8:27:00
lukego
I'm using magit and git blame. user error perhaps, but a comment might be more appropriate than a commit message...
8:28:50
lukego
ffs, I'm just trying to solve a problem here, preferably in a way that's future proof and helps other people. I don't get what's with all these sphynx-like answers. anyway.
8:29:25
jackdaniel
hm, I've helped you to find the rationale, digged the wayback archive, and still I'm getting punched on the face
11:16:34
theothornhill
How do I get (asdf:test-system :system) to yield an exit code of 1 when tests fail in rove? I am using `sbcl --non-interactive --load test.lisp` in a `test.sh` to run on ci, but it alwas passes with error code 0
11:20:24
jackdaniel
so you need to either use whatever the /actual/ testing framework gives you to run the testing function (and take the result)
11:20:47
jackdaniel
or you may try some fancy specialization on the method operate specialized on your system and the test-op
11:22:39
jackdaniel
it certainly doesn't fail for me when I run 5am tests, perhaps when the framework itself signals an error then test-system doesn't handle it?
11:23:01
theothornhill
Now the :perform inside the testsystem is (test-op (o c) (symbol-call :rove '#:run :gql/tests))
11:24:46
jackdaniel
the most silly solution (much to my liking) would be: (test-op (o c) (handler-bind ((tests-failed (lambda (c) (signal 'vroom))) (symbol-call …))) and then (handler-case (test-system ...) (vroom () (exit :code 1)))
11:25:17
jackdaniel
or (if rove signals say tests-failed) then (handler-case (test-system ...) (tests-failed () (exit :code 1))
11:26:54
theothornhill
it looks like it just returns two values, one list with successes, and one with fails. So I guess I could just check for nil in the second value
11:31:21
jackdaniel
it might be aesthetics - the function returns t on success (instead of - the function returns undefined value(s))
11:32:32
theothornhill
hmm. Well, so this works: (multiple-value-bind (foo bar fails) (rove::run :gql/tests)
11:36:22
jackdaniel
theothornhill: you may always signal some non-serious condition that may be optionally handled from above test-system
11:38:20
theothornhill
You mean wrapping the test-system call in a handler-bind or something like that?
11:39:46
jackdaniel
but yes, that's what I mean, and signal from operate. then when you call test-system interactively without handlers, it will simply return t
11:41:09
theothornhill
Right, I see what you mean. Yeah, that is better that what I do now, at least
12:09:11
phantomics
question about ABCL: my understanding is that it supports some CFFI functionality, but when I try to load a system with a simple CFFI dependency, the dependency breaks. Does CFFI actually not work with ABCL?
12:42:51
lisp123w
Does asdf re-search all directories every time one runs asdf:load-system or only on startup?
12:44:15
jackdaniel
it doesn't, it caches results and uses timestamps to determine whether something has changed
12:53:17
jackdaniel
perhaps it is possible for cffi to signal error like "Please install Maven or something" when it is not installed
12:54:51
etimmons
I think ABCL does that, asking with a restart to install it, but I forget right now how it's triggered
12:56:26
phantomics
Is there a way to check whether Maven is installed within ABCL? That way I can implement a fallback option in case it's not there
13:00:14
scymtym
lisp123w: if you create a new system definition file after ASDF has already been initialized, (ASDF:LOAD-SYSTEM "new-system") will signal an error. in the context of that error, there will be a restart CLEAR-CONFIGURATION-AND-RETRY which instructs ASDF to re-scan the filesystem and discover the new system definition file
13:04:26
etimmons
phantomics: I'm pretty sure there is, but I don't recall how. You can likely find it if you require :abcl-contrib and then apropos for maven or mvn
13:04:46
jackdaniel
I don't think that Java deserves such harsh opinion, but I'll keep quiet I'm getting into offtopic
13:12:46
puchacz
pattern like (list :foo x x) is interpreted as an attempt to rebind a variable already bound
13:13:51
phantomics
puchacz: you'd need to match them separately, like (list :foo (guard first3 (= first3 3)) (guard second3 (= second3 3)))
13:14:42
phantomics
I went looking for a way in trivia to do things like "match however many elements you find that fulfill this criteria" but couldn't find any