How to work with javascript promises in clojurescript? - interop

I have a problem with js promises:
I'm trying to convert this js code:
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
And I have the following:
(go
(let [result (<!
(.createToken stripe #(subscribe [:card-element]))
)]
(prn "result is" result)
;; (if (.-error result)
;; (.textContent (js/document.getElementById "card-errors") (.-message .-error result))
;; (prn "response is" (js/stripeTokenHandler (.-token result)))
;; )
)
)
But I get "No protocol method ReadPort.take! defined for type object: [object Promise]"
How do I do the js .then() part in cljs?

It seems you are a little bit confused with JavaScript interop. You can take a look at the Cheatsheet under the JavaScript Interop section.
Here are some quick examples:
JS CLJS
object.method(arg1, arg2) <=> (.method object arg1 arg2)
object.field <=> (.-field object)
object.field = "foo" <=> (set! (.-field object) "foo")
object.nested.field <=> (.-field (.-nested object))
To improve readability, you can use the -> arrow macro:
object.nested.field <=> (-> object .-nested .-field)
You can then rewrite your example as:
(-> (.createToken stripe card)
(.then (fn [result]
(if-let [error (.-error result)]
(-> (.getElementById js/document "card-errors")
(.-textContent)
(set! (.-message error)))
(js/stripeTokenHandler (.-token result)))))
;; if there is a `catch` branch
(.catch (fn […] …)))

Related

Getting the output of a process

I am trying to create a function which takes as input a path and returns the output of the ls terminal command as a string. I'm using a process and sentinel since I'll eventually want to create other functions which will take some time to execute, and I want them to run asynchronously.
(defun ls-to-string (path)
(let (ls-proc
ls-output)
(progn (setq ls-proc (start-process "" "ls-buffer" "ls" path))
(set-process-sentinel ls-proc (lambda (p e)
(if (string= e "finished\n")
(progn (set-buffer "ls-buffer")
(setq ls-output (buffer-string))
(kill-buffer "ls-buffer")
(message ls-output))))) <---- (1)
ls-output))) <---- (2)
(ls-to-string "/home")
I have (temporarily) added (message ls-output) just to show that ls-output does contain the string (1). However the return value is nil (2).

WebSocket error in common lisp

I want to make slack bot.
I can not solve this error.
(ql:quickload '(:cl-slack
:event-emitter
:websocket-driver
:jonathan
:cl-async
)
:silent t)
(defconstant +token+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
(defconstant +channel+ "xxx")
(defvar *client* (make-instance 'cl-slack.core:slack-client
:token +token+))
(let ((url (getf (jonathan:parse (cl-slack.rtm:start *client* nil)) :|url|)))
(format t url)
(defparameter *slack-bot* (wsd:make-client url)))
(defun params (id type channel text)
(jonathan:to-json (list :|id| id
:|type| type
:|channel| channel
:|text| text)))
(wsd:on :message *slack-bot*
(lambda (message)
(let ((data (jonathan:parse message)))
(format t "~A~%" data)
(when (string= (getf data :|type|) "message")
(wsd:send *slack-bot*
(params 1
"message"
(getf data :|channel|)
(getf data :|text|)))))))
(as:with-event-loop (:catch-app-errors t)
(wsd:start-connection *slack-bot*))
error is
[20:42:25] cl-async-util - handle-error: SSL verify error: 20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY

LISP - get all method names from a class

Can I get in LISP all the method names from a class?
Actually I need the methods, which have
set-
in their names.
For LispWorks:
(defun find-all-methods (class prefix)
(loop for method in (clos:specializer-direct-methods class)
for gf = (method-generic-function method)
for fname = (generic-function-name gf)
for fname-string = (when (symbolp fname) (symbol-name fname))
when (and (stringp fname-string)
(>= (length fname-string)
(length prefix))
(string= fname-string prefix
:end1 (length prefix)
:end2 (length prefix)))
collect method))
Example:
CL-USER 20 > (pprint (find-all-methods (find-class 'capi:button) "PRINT-"))
(#<STANDARD-METHOD CAPI:PRINT-COLLECTION-ITEM NIL (CAPI:BUTTON T) 40E06173D3>
#<STANDARD-METHOD CAPI:PRINT-CAPI-BUTTON NIL (CAPI:BUTTON) 40E05F9DDB>)

ANTLR grammar for scheme R5RS

I'm beginner in ANTLR and I'm learning it by an example. I use C as my target language.
The example is a Scheme R5RS grammar file taken from this question, with a little modification(rename the grammar name and add some options with the grammar specification untouched).
antlr generated the lexer and parser, and I compile it with a test main() in which I just do some initialization and simply call the parser. When runing the test program with a piece of scheme code, the parser detect some syntax error(which should not happen!)
main function in test.c
#include <stdio.h>
#include "r5rsLexer.h"
#include "r5rsParser.h"
int main(int argc, char *argv[])
{
pANTLR3_UINT8 fname;
pANTLR3_INPUT_STREAM input;
pr5rsLexer lexer;
pANTLR3_COMMON_TOKEN_STREAM tstream;
pr5rsParser parser;
r5rsParser_parse_return parse_return;
if (argc != 2)
{
ANTLR3_FPRINTF(stderr, "usage: %s file\n", argv[0]);
exit(1);
}
fname = (pANTLR3_UINT8)argv[1];
input = antlr3FileStreamNew(fname, ANTLR3_ENC_8BIT);
if (!input)
{
ANTLR3_FPRINTF(stderr, "open file stream failed\n");
exit(1);
}
lexer = r5rsLexerNew(input);
if (!lexer)
{
ANTLR3_FPRINTF(stderr, "new lexer failed\n");
exit(1);
}
tstream =
antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));
if (!tstream)
{
ANTLR3_FPRINTF(stderr, "open token stream failed\n");
exit(1);
}
parser = r5rsParserNew(tstream);
if (!parser)
{
ANTLR3_FPRINTF(stderr, "new parser failed\n");
exit(1);
}
parse_return = parser->parse(parser);
printf("succeed!\n");
return 0;
}
scheme code in test.scm:
(define-syntax should-be
(syntax-rules ()
((_ test-id value expression)
(let ((return-value expression))
(if (not (equal? return-value value))
(for-each (lambda (v) (display v))
`("Failure: " test-id ", expected '"
value "', got '" ,return-value "'." #\newline))
(for-each (lambda (v) (display v))
'("Passed: " test-id #\newline)))))))
(should-be 1.1 0
(let ((cont #f))
(letrec ((x (call-with-current-continuation (lambda (c) (set! cont c) 0)))
(y (call-with-current-continuation (lambda (c) (set! cont c) 0))))
(if cont
(let ((c cont))
(set! cont #f)
(set! x 1)
(set! y 1)
(c 0))
(+ x y)))))
the terminal output:
$> ls
r5rs.g test.c test.scm
$> antlr3 r5rs.g
$> ls
r5rs.g r5rs.tokens r5rsLexer.c r5rsLexer.h r5rsParser.c r5rsParser.h test.c test.scm
$> gcc -o test test.c r5rsLexer.c r5rsParser.c -lantlr3c
$> ./test test.scm
test.scm(1) : error 4 : Unexpected token, at offset 0
near [Index: 1 (Start: 154513905-Stop: 154513917) ='define-syntax', type<5> Line:1
LinePos:0]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 3
near [Index: 8 (Start: 154513932-Stop: 154513943) ='syntax-rules', type<7> Line: 2
LinePos:3]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 17
near [Index: 11 (Start: 154513946-Stop: 154513946) =')', type<82> Line: 2 LinePos:17]
: unexpected input...
expected one of : <EOR>
test.scm(2) : error 4 : Unexpected token, at offset 17
near [Index: 11 (Start: 154513946-Stop: 154513946) =')', type<82> Line: 2 LinePos:17]
: unexpected input...
expected one of : <EOR>
I've read through the grammar specification and it is correct. I can't figure out where the problem lies ... can someone help? thanks!
===================== reply =========================
Following the grammar rule of pattern and template, I went down to the code fragment below. I think the parse is going to match template with it and failed because template doesn't have an quasiquote alternative.
`("Failure: " test-id ", expected '" value "', got '" ,return-value "'." #\newline)
I believe the grammar rule for template follows the R5RS specification correctly, and the code is accepted by other R5Rs scheme implementation(I tested it in scheme48 and guile). How can this happen?
I think there must be something wrong in my analyse ...
It is a back-tick in
`("Failure: " test-id ", expected '"
that trips the parser.
If you follow grammar rules for pattern and template, you'll see that they don't reach quasiquotation rule that match both QUASIQUOTE and back-tick. They do however reach expressionKeyword that contains QUASIQUOTE.
You should fix grammar to include abbreviated forms in template or fix your input not to use them.

Collect lines of a buffer

There's process output that needs to be parsed per line, into structs.
sug skProc strutils.capitalize proc (string): string{.noSideEffect.}
sug skProc strutils.quoteIfContainsWhite proc (string): string
sug skProc system.gorge proc (string, string): string
sug skProc system.of proc (T, S): bool{.noSideEffect.}
sug skProc system.definedInScope proc (expr): bool{.noSideEffect.}
sug skIterator system.items iterator (cstring): char{.inline.}
sug skProc system.ord proc (T): int{.noSideEffect.}
This data is inside a buffer. So how do I read each line and pass it
to a function which returns a parsed representation and collect all
lines in the end?
EDIT: The code for parsing the lines (not debugged):
(defstruct nimrod-sug type namespace name signature)
(defun nimrod-parse-suggestion-line (line)
(let ((split (split-string line "[\t\n]")))
(make-nimrod-sug
:type (nth 1 split)
:namespace (first (split-string (nth 2 split) "\\."))
:name (second (split-string (nth 2 split) "\\."))
:signature (nth 3 split))
With some minor changes to the parser:
(defun nimrod-parse-suggestion-line (line)
(destructuring-bind (_ type fn &rest sig) (split-string line "[[:space:]]+" t)
(make-nimrod-sug :type type
:namespace (first (split-string fn "\\."))
:name (second (split-string fn "\\."))
:signature (apply 'concat sig))))
Assuming the name of the buffer is *output*, you can parse it like so:
(with-current-buffer "*output*"
(mapcar 'nimrod-parse-suggestion-line
(split-string (buffer-string) "[\r\n]" t)))
; => ([cl-struct-nimrod-sug "skProc" "strutils" "capitalize" "proc(string):string{.noSideEffect.}"] ...)
If you're currently visiting the output buffer, you won't need the with-current-buffer wrapper.

Resources