implement most of the TS version
This commit is contained in:
parent
3f90dda2e7
commit
e553b51dc0
|
@ -1,5 +1,24 @@
|
|||
import { BinExpr, emitCont, Result } from './Parse.js';
|
||||
import { BinExpr, emitBack, emitCont, isCont, result, Result } from './Parse.js';
|
||||
|
||||
export function evalBin(b: Result<BinExpr>): Result<number> {
|
||||
return emitCont(0, b.rem); // TODO
|
||||
if (isCont(b)) {
|
||||
const br = result(b);
|
||||
|
||||
if (br.lhs.type === 'digit' && br.oper.type === 'oper' && br.rhs.type === 'digit') {
|
||||
switch (br.oper.val) {
|
||||
case '+':
|
||||
return emitCont(br.lhs.val + br.rhs.val, b.rem);
|
||||
case '-':
|
||||
return emitCont(br.lhs.val - br.rhs.val, b.rem);
|
||||
case '*':
|
||||
return emitCont(br.lhs.val * br.rhs.val, b.rem);
|
||||
case '/':
|
||||
return emitCont(br.lhs.val / br.rhs.val, b.rem);
|
||||
default:
|
||||
return emitBack(b.rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return emitBack(b.rem);
|
||||
}
|
|
@ -32,3 +32,11 @@ export function isJust<T>(m: Maybe<T>): m is Just<T> {
|
|||
export function isNothing<T>(m: Maybe<T>): m is Nothing {
|
||||
return Object.getOwnPropertyDescriptor(m, SymbolNothing) !== undefined;
|
||||
}
|
||||
|
||||
export function mustExist<T>(m: T | undefined): T {
|
||||
if (m === undefined) {
|
||||
throw new Error('this is where things start to go wrong');
|
||||
} else {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { isJust, isNothing, Just, just, Maybe, Nothing, nothing } from './Maybe.js';
|
||||
import { map, split } from './Util.js';
|
||||
import { isJust, isNothing, Just, just, Maybe, mustExist, Nothing, nothing, SymbolJust } from './Maybe.js';
|
||||
import { map, primStringToList, split } from './Util.js';
|
||||
|
||||
export type Token = {
|
||||
type: 'digit';
|
||||
|
@ -17,6 +17,33 @@ export type Token = {
|
|||
type: 'term';
|
||||
};
|
||||
|
||||
export function digit(val: number): Token {
|
||||
return {
|
||||
type: 'digit',
|
||||
val,
|
||||
};
|
||||
}
|
||||
|
||||
export function oper(val: string): Token {
|
||||
return {
|
||||
type: 'oper',
|
||||
val,
|
||||
};
|
||||
}
|
||||
|
||||
export function skip(val: string): Token {
|
||||
return {
|
||||
type: 'skip',
|
||||
val,
|
||||
};
|
||||
}
|
||||
|
||||
export function term(): Token {
|
||||
return {
|
||||
type: 'term',
|
||||
};
|
||||
}
|
||||
|
||||
export interface BinExpr {
|
||||
oper: Token;
|
||||
lhs: Token;
|
||||
|
@ -25,21 +52,36 @@ export interface BinExpr {
|
|||
|
||||
export interface Result<T, R = Maybe<T>> {
|
||||
res: R;
|
||||
rem: Array<string>;
|
||||
rem: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export function emitCont<T>(val: T, rem: Array<string>): Result<T> {
|
||||
export const DIGITS = primStringToList("0123456789");
|
||||
export const OPERS = primStringToList("-+*/");
|
||||
export const SKIPS = primStringToList(" ");
|
||||
|
||||
export function emit<T>(val: Maybe<T>, rem: ReadonlyArray<string>): Result<T> {
|
||||
return {
|
||||
res: val,
|
||||
rem,
|
||||
};
|
||||
}
|
||||
|
||||
export function emitBack<T>(rem: ReadonlyArray<string>): Result<T> {
|
||||
return {
|
||||
res: nothing(),
|
||||
rem,
|
||||
};
|
||||
}
|
||||
|
||||
export function emitCont<T>(val: T, rem: ReadonlyArray<string>): Result<T> {
|
||||
return {
|
||||
res: just(val),
|
||||
rem,
|
||||
};
|
||||
}
|
||||
|
||||
export function emitBack<T>(rem: Array<string>): Result<T> {
|
||||
return {
|
||||
res: nothing(),
|
||||
rem,
|
||||
};
|
||||
export function result<T>(r: Result<T, Just<T>>): T {
|
||||
return r.res[SymbolJust];
|
||||
}
|
||||
|
||||
export function isCont<T>(r: Result<T>): r is Result<T, Just<T>> {
|
||||
|
@ -50,34 +92,133 @@ export function isBack<T>(r: Result<T>): r is Result<T, Nothing> {
|
|||
return isNothing(r.res);
|
||||
}
|
||||
|
||||
export function takeCons(cs: Array<string>, xs: Array<string>): Result<Array<string>> {
|
||||
return emitBack([]); // TODO
|
||||
export function takeCons(cs: ReadonlyArray<string>, xs: ReadonlyArray<string>): Result<ReadonlyArray<string>> {
|
||||
const acc: Array<string> = [];
|
||||
const rem = Array.from(xs);
|
||||
|
||||
while (cs.includes(rem[0])) {
|
||||
acc.push(mustExist(rem.shift()));
|
||||
}
|
||||
|
||||
return emitCont(acc, rem)
|
||||
}
|
||||
|
||||
export function ignoreConst(cs: Array<string>, xs: Array<string>): Array<string> {
|
||||
return xs; // TODO
|
||||
export function ignoreCons(cs: ReadonlyArray<string>, xs: ReadonlyArray<string>): ReadonlyArray<string> {
|
||||
const rem = Array.from(xs);
|
||||
|
||||
while (cs.includes(rem[0])) {
|
||||
rem.shift();
|
||||
}
|
||||
|
||||
return rem;
|
||||
}
|
||||
|
||||
export function parseChar(): Result<Token> {
|
||||
return emitBack([]); // TODO
|
||||
export function parseChar(c: string): Token {
|
||||
switch (c) {
|
||||
case '0':
|
||||
return digit(0);
|
||||
case '1':
|
||||
return digit(1);
|
||||
case '2':
|
||||
return digit(2);
|
||||
case '3':
|
||||
return digit(3);
|
||||
case '4':
|
||||
return digit(4);
|
||||
case '5':
|
||||
return digit(5);
|
||||
case '6':
|
||||
return digit(6);
|
||||
case '7':
|
||||
return digit(7);
|
||||
case '8':
|
||||
return digit(8);
|
||||
case '9':
|
||||
return digit(9);
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
return oper(c);
|
||||
case ' ':
|
||||
return skip(c);
|
||||
default:
|
||||
return {
|
||||
type: 'term',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function parseNat(): Result<number> {
|
||||
return emitBack([]); // TODO
|
||||
export function parseNat(a: Maybe<number>, cs: ReadonlyArray<string>): Result<number> {
|
||||
if (cs.length === 0) {
|
||||
return emit(a, []);
|
||||
}
|
||||
|
||||
const [x, ...xs] = cs;
|
||||
const t = parseChar(x);
|
||||
|
||||
if (t.type === 'digit') {
|
||||
return emitCont(t.val, xs)
|
||||
} else {
|
||||
return emitBack(cs);
|
||||
}
|
||||
}
|
||||
|
||||
export function takeNat(): Result<number> {
|
||||
return emitBack([]); // TODO
|
||||
export function takeNat(s: ReadonlyArray<string>): Result<number> {
|
||||
const cs = takeCons(DIGITS, s);
|
||||
|
||||
if (isCont(cs)) {
|
||||
const n = parseNat(nothing(), result(cs));
|
||||
|
||||
if (isCont(n)) {
|
||||
return emitCont(result(n), cs.rem);
|
||||
}
|
||||
}
|
||||
|
||||
return emitBack(cs.rem);
|
||||
}
|
||||
|
||||
export function parseOper() {}
|
||||
export function parseOper(s: ReadonlyArray<string>): Result<Token> {
|
||||
if (s.length === 0) {
|
||||
return emitBack([]);
|
||||
}
|
||||
|
||||
export function takeOper(): Result<Token> {
|
||||
return emitBack([]); // TODO
|
||||
const [x, ...xs] = s;
|
||||
const o = parseChar(x);
|
||||
|
||||
if (o.type === 'oper') {
|
||||
return emitCont(o, xs);
|
||||
} else {
|
||||
return emitBack(xs);
|
||||
}
|
||||
}
|
||||
|
||||
export function takeBin(): Result<BinExpr> {
|
||||
return emitBack([]); // TODO
|
||||
export function takeOper(s: ReadonlyArray<string>): Result<Token> {
|
||||
return parseOper(s);
|
||||
}
|
||||
|
||||
export function takeBin(s: ReadonlyArray<string>): Result<BinExpr> {
|
||||
const lhs = takeNat(ignoreCons(SKIPS, s));
|
||||
|
||||
if (isCont(lhs)) {
|
||||
const oper = takeOper(ignoreCons(SKIPS, lhs.rem));
|
||||
|
||||
if (isCont(oper)) {
|
||||
const rhs = takeNat(ignoreCons(SKIPS, oper.rem));
|
||||
|
||||
if (isCont(rhs)) {
|
||||
const bin: BinExpr = {
|
||||
lhs: digit(result(lhs)),
|
||||
rhs: digit(result(rhs)),
|
||||
oper: result(oper),
|
||||
};
|
||||
|
||||
return emitCont(bin, rhs.rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return emitBack(s);
|
||||
}
|
||||
|
||||
export function takeLine(c: Array<string>): Array<Result<BinExpr>> {
|
||||
|
|
|
@ -5,14 +5,14 @@ export function show(n: number): string {
|
|||
return n.toString();
|
||||
}
|
||||
|
||||
export function showList<T>(f: (t: T) => string, arr: Array<T>): string {
|
||||
export function showList<T>(f: (t: T) => string, arr: ReadonlyArray<T>): string {
|
||||
return arr.map(f).join(', ');
|
||||
}
|
||||
|
||||
export function showResult<T>(f: (t: T) => string, r: Result<T>): string {
|
||||
if (isCont(r)) {
|
||||
return f(r.res[SymbolJust]);
|
||||
return 'result: ' + f(r.res[SymbolJust]);
|
||||
} else {
|
||||
return r.rem.join('');
|
||||
return 'remainder: ' + r.rem.join('');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue