summary:
- type conversions
- JavaScript's Boolean(), Number() and String()
console.log
and+
now implicitly convert its arguemnts into String
- function literal without closure
(function(x) { console.log(x); })(2)
works
Type conversions: Boolean(), Number() and String()
https://github.com/ujihisa/jinaw/commit/f28e7f55559f4919d6718539d413f0e65bd4a9e0
(defn js-boolean
"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Boolean"
[value]
(not (get #{0 'null false 'NaN 'undefined} value false)))
(defn js-number
"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number"
[value]
(condp instance? value
String (if (empty? value)
0
(let [x (read-string value)]
(if (number? x) x 'NaN)))
Long value
'NaN))
(defn js-string
"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String"
[value]
(.toString value))
Looks fairly straightforward.
Type conversions in + operator
It works both for numbers and strings.
The rule which to choose is really simple. If either one of the operands is not a number, it chooses the string's one and converts both operands to strings.
> 1 + 2 3 > '1' + 2 "12" > 1 + '2' "12" > '1' + '2' "12" > [1] + [2] "12" > 1 + [2] "12"
so
(defn evaluate [expr env]
"assumption: env won't change"
(if (list? expr)
(let [[car & cdr] expr]
(case car
fcall (let [func (evaluate (first cdr) env)
args (map #(evaluate % env) (second cdr))]
(case func
console.log (println (js-string (first args)))
+ (if (every? number? args)
(+ (first args) (second args))
(str (js-string (first args)) (js-string (second args))))
(prn 'must-not-happen 'missing-function func)))
quote (get env (first cdr))
expr))
expr))
now the runtime outputs "1hello" by console.log(1 + 'hello')
.
function literal without closure
https://github.com/ujihisa/jinaw/commit/a50de0f344951e2e36a60131458d8533ea75241a
A function object which doesn't have lexical scope is represented simply as a tuple of parameter names and body (a sequence of statements.) Here just for readability in the future I'll use a hash-map which has :type
, :params
, and :body
for function objects.
(defn evaluate [expr env]
"assumption: env won't change"
(if (list? expr)
(let [[car & cdr] expr]
(case car
function (let [params (first cdr)
body (second cdr)]
{:type :function :params params :body body})
fcall (let [func (evaluate (first cdr) env)
args (map #(evaluate % env) (second cdr))]
(case func
console.log (println (js-string (first args)))
+ (if (every? number? args)
(+ (first args) (second args))
(if (= (:type func) :function)
(let [applied-params (into {} (map (fn [x y] [x y])
(:params func)
args))]
(run- (:body func) (merge env applied-params)))
(prn 'must-not-happen 'missing-function func))))
quote (get env (first cdr) 'missing-local-var)
...snip...
It doesn't support return
yet.
No comments:
Post a Comment