mirror of
https://github.com/kanaka/mal.git
synced 2024-09-19 17:47:53 +03:00
rename MalNull to MalNil
This commit is contained in:
parent
5bb7479da5
commit
6071876ffe
46
ts/core.ts
46
ts/core.ts
@ -2,7 +2,7 @@ import * as fs from "fs";
|
||||
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalSymbol, MalFunction, MalNull, MalList, MalVector, MalBoolean, MalNumber, MalString, MalKeyword, MalHashMap, MalAtom, equals, isSeq } from "./types";
|
||||
import { Node, MalType, MalSymbol, MalFunction, MalNil, MalList, MalVector, MalBoolean, MalNumber, MalString, MalKeyword, MalHashMap, MalAtom, equals, isSeq } from "./types";
|
||||
import { readStr } from "./reader";
|
||||
import { prStr } from "./printer";
|
||||
|
||||
@ -16,7 +16,7 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
},
|
||||
|
||||
"nil?"(v: MalType) {
|
||||
return new MalBoolean(v.type === Node.Null);
|
||||
return new MalBoolean(v.type === Node.Nil);
|
||||
},
|
||||
"true?"(v: MalType) {
|
||||
return new MalBoolean(v.type === Node.Boolean && v.v);
|
||||
@ -52,15 +52,15 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
"str"(...args: MalType[]): MalString {
|
||||
return new MalString(args.map(v => prStr(v, false)).join(""));
|
||||
},
|
||||
prn(...args: MalType[]): MalNull {
|
||||
prn(...args: MalType[]): MalNil {
|
||||
const str = args.map(v => prStr(v, true)).join(" ");
|
||||
console.log(str);
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
},
|
||||
println(...args: MalType[]): MalNull {
|
||||
println(...args: MalType[]): MalNil {
|
||||
const str = args.map(v => prStr(v, false)).join(" ");
|
||||
console.log(str);
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
},
|
||||
"read-string"(v: MalType) {
|
||||
if (v.type !== Node.String) {
|
||||
@ -75,7 +75,7 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
|
||||
const ret = readline(v.v);
|
||||
if (ret == null) {
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
}
|
||||
|
||||
return new MalString(ret);
|
||||
@ -203,8 +203,8 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
return v.dissoc(args);
|
||||
},
|
||||
get(v: MalType, key: MalType) {
|
||||
if (v.type === Node.Null) {
|
||||
return MalNull.instance;
|
||||
if (v.type === Node.Nil) {
|
||||
return MalNil.instance;
|
||||
}
|
||||
if (v.type !== Node.HashMap) {
|
||||
throw new Error(`unexpected symbol: ${v.type}, expected: hash-map`);
|
||||
@ -213,11 +213,11 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
throw new Error(`unexpected symbol: ${key.type}, expected: string or keyword`);
|
||||
}
|
||||
|
||||
return v.get(key) || MalNull.instance;
|
||||
return v.get(key) || MalNil.instance;
|
||||
},
|
||||
"contains?"(v: MalType, key: MalType) {
|
||||
if (v.type === Node.Null) {
|
||||
return MalNull.instance;
|
||||
if (v.type === Node.Nil) {
|
||||
return MalNil.instance;
|
||||
}
|
||||
if (v.type !== Node.HashMap) {
|
||||
throw new Error(`unexpected symbol: ${v.type}, expected: hash-map`);
|
||||
@ -281,17 +281,17 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
return v;
|
||||
},
|
||||
first(v: MalType) {
|
||||
if (v.type === Node.Null) {
|
||||
return MalNull.instance;
|
||||
if (v.type === Node.Nil) {
|
||||
return MalNil.instance;
|
||||
}
|
||||
if (!isSeq(v)) {
|
||||
throw new Error(`unexpected symbol: ${v.type}, expected: list or vector`);
|
||||
}
|
||||
|
||||
return v.list[0] || MalNull.instance;
|
||||
return v.list[0] || MalNil.instance;
|
||||
},
|
||||
rest(v: MalType) {
|
||||
if (v.type === Node.Null) {
|
||||
if (v.type === Node.Nil) {
|
||||
return new MalList([]);
|
||||
}
|
||||
if (!isSeq(v)) {
|
||||
@ -310,7 +310,7 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
if (isSeq(v)) {
|
||||
return new MalNumber(v.list.length);
|
||||
}
|
||||
if (v.type === Node.Null) {
|
||||
if (v.type === Node.Nil) {
|
||||
return new MalNumber(0);
|
||||
}
|
||||
throw new Error(`unexpected symbol: ${v.type}`);
|
||||
@ -353,31 +353,31 @@ export const ns: Map<MalSymbol, MalFunction> = (() => {
|
||||
seq(v: MalType) {
|
||||
if (v.type === Node.List) {
|
||||
if (v.list.length === 0) {
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (v.type === Node.Vector) {
|
||||
if (v.list.length === 0) {
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
}
|
||||
return new MalList(v.list);
|
||||
}
|
||||
if (v.type === Node.String) {
|
||||
if (v.v.length === 0) {
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
}
|
||||
return new MalList(v.v.split("").map(s => new MalString(s)));
|
||||
}
|
||||
if (v.type === Node.Null) {
|
||||
return MalNull.instance;
|
||||
if (v.type === Node.Nil) {
|
||||
return MalNil.instance;
|
||||
}
|
||||
|
||||
throw new Error(`unexpected symbol: ${v.type}, expected: list or vector or string`);
|
||||
},
|
||||
|
||||
meta(v: MalType) {
|
||||
return v.meta || MalNull.instance;
|
||||
return v.meta || MalNil.instance;
|
||||
},
|
||||
"with-meta"(v: MalType, m: MalType) {
|
||||
return v.withMeta(m);
|
||||
|
@ -30,7 +30,7 @@ export function prStr(v: MalType, printReadably = true): string {
|
||||
} else {
|
||||
return v.v;
|
||||
}
|
||||
case Node.Null:
|
||||
case Node.Nil:
|
||||
return "nil";
|
||||
case Node.Keyword:
|
||||
return `:${v.v}`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { MalType, MalList, MalString, MalNumber, MalBoolean, MalNull, MalKeyword, MalSymbol, MalVector, MalHashMap } from "./types";
|
||||
import { MalType, MalList, MalString, MalNumber, MalBoolean, MalNil, MalKeyword, MalSymbol, MalVector, MalHashMap } from "./types";
|
||||
|
||||
class Reader {
|
||||
position = 0;
|
||||
@ -134,7 +134,7 @@ function readAtom(reader: Reader): MalType {
|
||||
}
|
||||
switch (token) {
|
||||
case "nil":
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
case "true":
|
||||
return new MalBoolean(true);
|
||||
case "false":
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalNull, MalList, MalVector, MalHashMap, MalFunction, isSeq } from "./types";
|
||||
import { Node, MalType, MalNil, MalList, MalVector, MalHashMap, MalFunction, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -91,7 +91,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -99,7 +99,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
return evalMal(elseExrp, env);
|
||||
} else {
|
||||
return MalNull.instance;
|
||||
return MalNil.instance;
|
||||
}
|
||||
}
|
||||
case "fn*": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalNull, MalList, MalVector, MalHashMap, MalFunction, isSeq } from "./types";
|
||||
import { Node, MalType, MalNil, MalList, MalVector, MalHashMap, MalFunction, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -91,7 +91,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -99,7 +99,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalString, MalNull, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Node, MalType, MalString, MalNil, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -91,7 +91,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -99,7 +99,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalString, MalNull, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Node, MalType, MalString, MalNil, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -138,7 +138,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -146,7 +146,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalString, MalNull, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Node, MalType, MalString, MalNil, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -202,7 +202,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -210,7 +210,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalString, MalNull, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isAST, isSeq } from "./types";
|
||||
import { Node, MalType, MalString, MalNil, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isAST, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -224,7 +224,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -232,7 +232,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readline } from "./node_readline";
|
||||
|
||||
import { Node, MalType, MalString, MalNull, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isAST, isSeq } from "./types";
|
||||
import { Node, MalType, MalString, MalNil, MalList, MalVector, MalHashMap, MalSymbol, MalFunction, isAST, isSeq } from "./types";
|
||||
import { Env } from "./env";
|
||||
import * as core from "./core";
|
||||
import { readStr } from "./reader";
|
||||
@ -224,7 +224,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
let b = true;
|
||||
if (ret.type === Node.Boolean && !ret.v) {
|
||||
b = false;
|
||||
} else if (ret.type === Node.Null) {
|
||||
} else if (ret.type === Node.Nil) {
|
||||
b = false;
|
||||
}
|
||||
if (b) {
|
||||
@ -232,7 +232,7 @@ function evalMal(ast: MalType, env: Env): MalType {
|
||||
} else if (elseExrp) {
|
||||
ast = elseExrp;
|
||||
} else {
|
||||
ast = MalNull.instance;
|
||||
ast = MalNil.instance;
|
||||
}
|
||||
continue loop;
|
||||
}
|
||||
|
28
ts/types.ts
28
ts/types.ts
@ -1,12 +1,12 @@
|
||||
import { Env } from "./env";
|
||||
|
||||
export type MalType = MalList | MalNumber | MalString | MalNull | MalBoolean | MalSymbol | MalKeyword | MalVector | MalHashMap | MalFunction | MalAtom;
|
||||
export type MalType = MalList | MalNumber | MalString | MalNil | MalBoolean | MalSymbol | MalKeyword | MalVector | MalHashMap | MalFunction | MalAtom;
|
||||
|
||||
export const enum Node {
|
||||
List = 1,
|
||||
Number,
|
||||
String,
|
||||
Null,
|
||||
Nil,
|
||||
Boolean,
|
||||
Symbol,
|
||||
Keyword,
|
||||
@ -21,7 +21,7 @@ export function equals(a: MalType, b: MalType, strict?: boolean): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type === Node.Null && b.type === Node.Null) {
|
||||
if (a.type === Node.Nil && b.type === Node.Nil) {
|
||||
return true;
|
||||
}
|
||||
if (isSeq(a) && isSeq(b)) {
|
||||
@ -39,7 +39,7 @@ export function equals(a: MalType, b: MalType, strict?: boolean): boolean {
|
||||
throw new Error(`unexpected symbol: ${aK.type}, expected: string or keyword`);
|
||||
}
|
||||
const bV = b.get(aK);
|
||||
if (aV.type === Node.Null && bV.type === Node.Null) {
|
||||
if (aV.type === Node.Nil && bV.type === Node.Nil) {
|
||||
continue;
|
||||
}
|
||||
if (!equals(aV, bV)) {
|
||||
@ -124,16 +124,24 @@ export class MalString {
|
||||
}
|
||||
}
|
||||
|
||||
export class MalNull {
|
||||
export class MalNil {
|
||||
|
||||
static instance = new MalNull();
|
||||
private static _instance?: MalNil;
|
||||
|
||||
type: Node.Null = Node.Null;
|
||||
static get instance(): MalNil {
|
||||
if (this._instance) {
|
||||
return this._instance;
|
||||
}
|
||||
this._instance = new MalNil();
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
type: Node.Nil = Node.Nil;
|
||||
meta?: MalType;
|
||||
|
||||
private constructor() { }
|
||||
|
||||
withMeta(_meta: MalType): MalNull {
|
||||
withMeta(_meta: MalType): MalNil {
|
||||
throw new Error(`not supported`);
|
||||
}
|
||||
}
|
||||
@ -254,9 +262,9 @@ export class MalHashMap {
|
||||
|
||||
get(key: MalKeyword | MalString) {
|
||||
if (key.type === Node.Keyword) {
|
||||
return this.keywordMap.get(key) || MalNull.instance;
|
||||
return this.keywordMap.get(key) || MalNil.instance;
|
||||
}
|
||||
return this.stringMap[key.v] || MalNull.instance;
|
||||
return this.stringMap[key.v] || MalNil.instance;
|
||||
}
|
||||
|
||||
entries(): [MalType, MalType][] {
|
||||
|
Loading…
Reference in New Issue
Block a user