1
0
Fork 0

implement most of the TS version

This commit is contained in:
Sean Sube 2022-09-30 22:23:23 -05:00
parent 3f90dda2e7
commit e553b51dc0
4 changed files with 197 additions and 29 deletions

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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()));
}
export function ignoreConst(cs: Array<string>, xs: Array<string>): Array<string> {
return xs; // TODO
return emitCont(acc, rem)
}
export function parseChar(): Result<Token> {
return emitBack([]); // TODO
export function ignoreCons(cs: ReadonlyArray<string>, xs: ReadonlyArray<string>): ReadonlyArray<string> {
const rem = Array.from(xs);
while (cs.includes(rem[0])) {
rem.shift();
}
export function parseNat(): Result<number> {
return emitBack([]); // TODO
return rem;
}
export function takeNat(): Result<number> {
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 parseOper() {}
export function takeOper(): Result<Token> {
return emitBack([]); // TODO
export function parseNat(a: Maybe<number>, cs: ReadonlyArray<string>): Result<number> {
if (cs.length === 0) {
return emit(a, []);
}
export function takeBin(): Result<BinExpr> {
return emitBack([]); // TODO
const [x, ...xs] = cs;
const t = parseChar(x);
if (t.type === 'digit') {
return emitCont(t.val, xs)
} else {
return emitBack(cs);
}
}
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(s: ReadonlyArray<string>): Result<Token> {
if (s.length === 0) {
return emitBack([]);
}
const [x, ...xs] = s;
const o = parseChar(x);
if (o.type === 'oper') {
return emitCont(o, xs);
} else {
return emitBack(xs);
}
}
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>> {

View File

@ -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('');
}
}