1
1
mirror of https://github.com/kanaka/mal.git synced 2024-08-17 17:50:24 +03:00
mal/impls/dart/types.dart
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

271 lines
5.1 KiB
Dart

import 'dart:collection';
import 'env.dart';
abstract class MalType {
bool get isMacro => false;
MalType meta;
MalType clone();
}
abstract class MalIterable extends MalType
with ListMixin<MalType>
implements List<MalType> {
final List<MalType> elements;
MalIterable(this.elements);
MalType operator [](int index) => elements[index];
void operator []=(int index, MalType value) {
elements[index] = value;
}
int get length => elements.length;
void set length(int newLength) {
elements.length = newLength;
}
bool operator ==(other) {
if (other is! MalIterable) return false;
// apparently (= (list) nil) should be false...
if (other is MalNil) return false;
if (elements.length != other.elements.length) return false;
for (var i = 0; i < elements.length; i++) {
if (elements[i] != other.elements[i]) return false;
}
return true;
}
@override
MalIterable clone();
}
class MalList extends MalIterable {
MalList(List<MalType> elements) : super(elements);
@override
MalList clone() {
return new MalList(elements.toList());
}
}
class MalVector extends MalIterable {
MalVector(List<MalType> elements) : super(elements);
@override
MalVector clone() {
return new MalVector(elements.toList());
}
}
class MalHashMap extends MalType {
final Map<MalType, MalType> value;
MalHashMap(this.value);
MalHashMap.fromSequence(List<MalType> elements)
: value = _mapFromSequence(elements);
static Map<MalType, MalType> _mapFromSequence(List<MalType> elements) {
var result = <MalType, MalType>{};
var readingKey = true;
MalType pendingKey;
for (var malType in elements) {
if (readingKey) {
if (malType is MalString || malType is MalKeyword) {
pendingKey = malType;
} else {
throw new ArgumentError('hash-map keys must be strings or keywords');
}
} else {
result[pendingKey] = malType;
}
readingKey = !readingKey;
}
return result;
}
bool operator ==(other) {
if (other is! MalHashMap) return false;
var otherMap = (other as MalHashMap).value;
if (otherMap.length != value.length) return false;
for (var key in value.keys) {
if (!otherMap.containsKey(key)) return false;
if (value[key] != otherMap[key]) return false;
}
return true;
}
@override
MalHashMap clone() {
return new MalHashMap(new Map.from(value));
}
}
class MalInt extends MalType {
final int value;
MalInt(this.value);
bool operator ==(other) {
if (other is! MalInt) return false;
return other.value == value;
}
@override
MalInt clone() {
return new MalInt(value);
}
}
class MalSymbol extends MalType {
final String value;
MalSymbol(this.value);
int get hashCode => value.hashCode;
bool operator ==(other) {
if (other is! MalSymbol) return false;
return value == other.value;
}
@override
MalSymbol clone() {
return new MalSymbol(value);
}
}
class MalKeyword extends MalType {
final String value;
MalKeyword(this.value);
int get hashCode => value.hashCode;
bool operator ==(other) {
if (other is! MalKeyword) return false;
return value == other.value;
}
@override
MalKeyword clone() {
return new MalKeyword(value);
}
}
class MalString extends MalType {
final String value;
MalString(this.value);
int get hashCode => value.hashCode;
bool operator ==(other) {
if (other is! MalString) return false;
return other.value == value;
}
@override
MalString clone() {
return new MalString(value);
}
}
class MalBool extends MalType {
final bool value;
MalBool(this.value);
bool operator ==(other) {
if (other is! MalBool) return false;
return other.value == value;
}
@override
MalBool clone() {
return new MalBool(value);
}
}
class MalNil extends MalIterable {
MalNil() : super(const <MalType>[]);
bool operator ==(other) => other is MalNil;
@override
MalNil clone() {
return new MalNil();
}
}
class MalAtom extends MalType {
MalType value;
MalAtom(this.value);
@override
MalAtom clone() {
return new MalAtom(value);
}
}
abstract class MalCallable extends MalType {
MalType call(List<MalType> args);
bool get isMacro => false;
}
typedef MalType BuiltinFunc(List<MalType> args);
class MalBuiltin extends MalCallable {
final BuiltinFunc func;
MalBuiltin(this.func);
MalType call(List<MalType> args) {
return func(args);
}
@override
MalBuiltin clone() {
return new MalBuiltin(func);
}
}
typedef MalType EvalFun(MalType ast, Env env);
class MalClosure extends MalCallable {
final List<MalSymbol> params;
final MalType ast;
final Env env;
final Function func;
@override
bool isMacro = false;
MalClosure(this.params, this.ast, this.env, this.func);
MalType call(List<MalType> args) {
return func(args);
}
@override
MalClosure clone() {
var closure =
new MalClosure(this.params.toList(), this.ast, this.env, this.func);
closure.isMacro = this.isMacro;
return closure;
}
}
class MalException implements Exception {
final MalType value;
MalException(this.value);
}