1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-19 09:38:28 +03:00
mal/impls/wren/core.wren
Nicolas Boulenguez fbfe6784d2 Change quasiquote algorithm
- Add a `vec` built-in function in step7 so that `quasiquote` does not
  require `apply` from step9.
- Introduce quasiquoteexpand special in order to help debugging step7.
  This may also prepare newcomers to understand step8.
- Add soft tests.
- Do not quote numbers, strings and so on.

Should ideally have been in separate commits:
- elisp: simplify and fix (keyword :k)
- factor: fix copy/paste error in let*/step7, simplify eval-ast.
- guile: improve list/vector types
- haskell: revert evaluation during quasiquote
- logo, make: cosmetic issues
2020-08-11 01:01:56 +02:00

107 lines
4.7 KiB
Plaintext

import "io" for File
import "./reader" for MalReader
import "./readline" for Readline
import "./printer" for Printer
import "./types" for MalVal, MalSymbol, MalSequential, MalList, MalVector, MalMap, MalNativeFn, MalFn, MalAtom, MalException
import "./interop" for Interop
class Core {
static fn(func) { MalNativeFn.new(func) }
static ns {
return {
"=": fn { |a| a[0] == a[1] },
"throw": fn { |a|
MalException.set(a[0])
Fiber.abort("___MalException___")
},
"nil?": fn { |a| a[0] == null },
"true?": fn { |a| a[0] == true },
"false?": fn { |a| a[0] == false },
"string?": fn { |a| a[0] is String && !MalVal.isKeyword(a[0]) },
"symbol": fn { |a| a[0] is MalSymbol ? a[0] : MalSymbol.new(a[0]) },
"symbol?": fn { |a| a[0] is MalSymbol },
"keyword": fn { |a| MalVal.isKeyword(a[0]) ? a[0] : MalVal.newKeyword(a[0]) },
"keyword?": fn { |a| MalVal.isKeyword(a[0]) },
"number?": fn { |a| a[0] is Num },
"fn?": fn { |a| a[0] is MalNativeFn || (a[0] is MalFn && !a[0].isMacro) },
"macro?": fn { |a| a[0] is MalFn && a[0].isMacro },
"pr-str": fn { |a| a.map { |e| Printer.pr_str(e, true) }.join(" ") },
"str": fn { |a| a.map { |e| Printer.pr_str(e, false) }.join() },
"prn": fn { |a|
System.print(a.map { |e| Printer.pr_str(e, true) }.join(" "))
return null
},
"println": fn { |a|
System.print(a.map { |e| Printer.pr_str(e, false) }.join(" "))
return null
},
"read-string": fn { |a| MalReader.read_str(a[0]) },
"readline": fn { |a| Readline.readLine(a[0]) },
"slurp": fn { |a| File.read(a[0]) },
"<": fn { |a| a[0] < a[1] },
"<=": fn { |a| a[0] <= a[1] },
">": fn { |a| a[0] > a[1] },
">=": fn { |a| a[0] >= a[1] },
"+": fn { |a| a[0] + a[1] },
"-": fn { |a| a[0] - a[1] },
"*": fn { |a| a[0] * a[1] },
"/": fn { |a| a[0] / a[1] },
"time-ms": fn { |a| (System.gettimeofday * 1000).floor },
"list": fn { |a| MalList.new(a) },
"list?": fn { |a| a[0] is MalList },
"vector": fn { |a| MalVector.new(a) },
"vector?": fn { |a| a[0] is MalVector },
"hash-map": fn { |a| MalMap.fromList(a) },
"map?": fn { |a| a[0] is MalMap },
"assoc": fn { |a| a[0].assoc(a[1...a.count]) },
"dissoc": fn { |a| a[0].dissoc(a[1...a.count]) },
"get": fn { |a| a[0] == null ? null : a[0].data[a[1]] },
"contains?": fn { |a| a[0].data.containsKey(a[1]) },
"keys": fn { |a| MalList.new(a[0].data.keys.toList) },
"vals": fn { |a| MalList.new(a[0].data.values.toList) },
"sequential?": fn { |a| a[0] is MalSequential },
"cons": fn { |a| MalList.new([a[0]] + a[1].elements) },
"concat": fn { |a| MalList.new(a.reduce([]) { |acc,e| acc + e.elements }) },
"vec": fn { |a| MalVector.new(a[0].elements) },
"nth": fn { |a| a[1] < a[0].count ? a[0][a[1]] : Fiber.abort("nth: index out of range") },
"first": fn { |a| a[0] == null ? null : a[0].first },
"rest": fn { |a| a[0] == null ? MalList.new([]) : a[0].rest },
"empty?": fn { |a| a[0].isEmpty },
"count": fn { |a| a[0] == null ? 0 : a[0].count },
"apply": fn { |a| a[0].call(a[1...(a.count - 1)] + a[-1].elements) },
"map": fn { |a| MalList.new(a[1].elements.map { |e| a[0].call([e]) }.toList) },
"conj": fn { |a|
if (a[0] is MalList) return MalList.new(a[-1..1] + a[0].elements)
if (a[0] is MalVector) return MalVector.new(a[0].elements + a[1..-1])
},
"seq": fn { |a|
if (a[0] == null) return null
if (a[0].count == 0) return null
if (a[0] is String) return MalList.new(a[0].toList)
if (a[0] is MalVector) return MalList.new(a[0].elements)
return a[0]
},
"meta": fn { |a| a[0].meta },
"with-meta": fn { |a|
var x = a[0].clone()
x.meta = a[1]
return x
},
"atom": fn { |a| MalAtom.new(a[0]) },
"atom?": fn { |a| a[0] is MalAtom },
"deref": fn { |a| a[0].value },
"reset!": fn { |a| a[0].value = a[1] },
"swap!": fn { |a| a[0].value = a[1].call([a[0].value] + a[2..-1]) },
"wren-eval": fn { |a| Interop.wren_eval(a[0]) }
}
}
}