This commit is contained in:
parent
d0fc9ca144
commit
77dc1ded9c
4 changed files with 228 additions and 13 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ node_modules
|
|||
/src/*.js
|
||||
/tests/*.js
|
||||
.vscode
|
||||
activate.sh
|
||||
|
|
2
activate.sh
Normal file
2
activate.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
PATH+=:~/桌面/TMP/ts-playground/clo/node_modules/.bin
|
107
src/index.js
107
src/index.js
|
@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.m1TType = void 0;
|
||||
exports.OnceOrMoreDo = exports.matchAny = exports.m1TType = exports.tkTreeToSExp = void 0;
|
||||
var fs = require('fs');
|
||||
const node_process_1 = require("node:process");
|
||||
const tk = __importStar(require("./tokenize.js"));
|
||||
|
@ -54,6 +54,28 @@ function slice(x, index, end) {
|
|||
throw new Error("the tkTree can't be concated, because it's not an array.");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* convert a `tkTree` AST to S-expr string
|
||||
* @param t the `tkTree`
|
||||
* @returns S-expr String
|
||||
*/
|
||||
function tkTreeToSExp(t) {
|
||||
var str = "";
|
||||
if (Array.isArray(t)) {
|
||||
let strArray = t.map((x) => tkTreeToSExp(x));
|
||||
str = "(" + strArray.join(" ") + ")";
|
||||
}
|
||||
else {
|
||||
if (t === undefined) {
|
||||
str = "%undefined";
|
||||
}
|
||||
else {
|
||||
str = t.text;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
exports.tkTreeToSExp = tkTreeToSExp;
|
||||
/**
|
||||
* @description
|
||||
* match one token type.
|
||||
|
@ -95,6 +117,7 @@ exports.m1TType = m1TType;
|
|||
* type int
|
||||
*/
|
||||
let tInt = m1TType(tk.TokenType.INT);
|
||||
let tId = m1TType(tk.TokenType.ID);
|
||||
let tAdd = m1TType(tk.TokenType.I_ADD);
|
||||
let tSub = m1TType(tk.TokenType.I_SUB);
|
||||
let tMul = m1TType(tk.TokenType.I_MUL);
|
||||
|
@ -141,6 +164,55 @@ function orDo(f1, f2) {
|
|||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param m : the `MatcheePair` to be consumed.
|
||||
* @returns if the length of `m.remained` >= 1; consumes the matchee by 1 token
|
||||
* and wraps it in `Some`,
|
||||
* otherwise, returns `None`.
|
||||
*/
|
||||
function matchAny(m) {
|
||||
if (m.remained.length >= 1) {
|
||||
return {
|
||||
_tag: "Some", value: {
|
||||
matched: m.matched.concat(m.remained[0]),
|
||||
remained: m.remained.slice(1),
|
||||
ast: [m.remained[0]],
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
return { _tag: "None" };
|
||||
}
|
||||
}
|
||||
exports.matchAny = matchAny;
|
||||
/**
|
||||
* @description repeating matching function `f`
|
||||
* zero or more times, like the asterisk `*` in regex `f*` .
|
||||
* @param f : the function to be repeated 0+ times.
|
||||
* @returns:the combined function
|
||||
*/
|
||||
function OnceOrMoreDo(f) {
|
||||
return (x) => {
|
||||
var wrappedOldX = { _tag: "Some", value: x };
|
||||
var wrappedNewX = wrappedOldX;
|
||||
var counter = -1;
|
||||
while (wrappedNewX._tag != "None") {
|
||||
wrappedOldX = wrappedNewX;
|
||||
wrappedNewX = thenDo(wrappedOldX, f);
|
||||
counter += 1;
|
||||
}
|
||||
;
|
||||
if (counter <= 0) {
|
||||
return { _tag: "None" };
|
||||
}
|
||||
let ast = wrappedOldX.value.ast;
|
||||
wrappedOldX.value.ast = ast.slice(ast.length - counter);
|
||||
console.log(repr(wrappedOldX.value.ast));
|
||||
return wrappedOldX;
|
||||
};
|
||||
}
|
||||
exports.OnceOrMoreDo = OnceOrMoreDo;
|
||||
/**
|
||||
* aux function for midfix operator
|
||||
* @param f function
|
||||
|
@ -174,12 +246,32 @@ let circumfix = (f, signal) => (x) => {
|
|||
let single1 = circumfix((x) => thenDo(thenDo(thenDo(tk.toSome(x), tLParen), expr), tRParen), "fac1");
|
||||
let single2 = tInt;
|
||||
let single = orDo(single1, single2);
|
||||
/** fac1 = single "(" int ")" | single */
|
||||
/** func = single | single "(" single ")"
|
||||
* i.e.
|
||||
*
|
||||
* func = single | func_aux ( int )
|
||||
*
|
||||
*/
|
||||
/** fac = single ["(" single ")"]? | single */
|
||||
let fac1Appliee = circumfix((x) => thenDo(thenDo(thenDo(tk.toSome(x), tLParen), tInt), tRParen), "fac1");
|
||||
let fac1 = (x) => {
|
||||
let n = thenDo(thenDo(toSome(x), single), fac1Appliee);
|
||||
console.log("+" + "bocchitherock" + "+" + repr(n));
|
||||
return n;
|
||||
let raw = thenDo(thenDo(toSome(x), single), OnceOrMoreDo(fac1Appliee));
|
||||
console.log("+" + "火鳥" + "+" + repr(raw));
|
||||
if (raw._tag == "Some") {
|
||||
var result = raw.value.ast[0];
|
||||
let applyToken = { text: '%apply', ln: 0, col: 0 };
|
||||
for (var i = 1; i < raw.value.ast.length; i++) {
|
||||
result = [applyToken, result, raw.value.ast[i]];
|
||||
}
|
||||
console.log("+" + "hitori" + "+" + repr(result));
|
||||
if (!Array.isArray(result)) {
|
||||
raw.value.ast = [result];
|
||||
}
|
||||
else {
|
||||
raw.value.ast = result;
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
};
|
||||
let fac2 = single;
|
||||
let fac = orDo(fac1, fac2);
|
||||
|
@ -210,7 +302,7 @@ let expr2 = term;
|
|||
* expr = expr1 | expr2
|
||||
*/
|
||||
let expr = orDo(expr1, expr2);
|
||||
let tokens = tk.tokenize("12(13)(14)");
|
||||
let tokens = tk.tokenize("1");
|
||||
//let tokens = tk.tokenize("(4-(3/4))");
|
||||
//tk.tokenize(argv[2]);
|
||||
let tokensFiltered = tokens.filter((x) => {
|
||||
|
@ -227,4 +319,7 @@ let beta = expr({
|
|||
remained: tokensFiltered,
|
||||
ast: []
|
||||
});
|
||||
if (beta._tag == "Some") {
|
||||
console.log(tkTreeToSExp(beta.value.ast));
|
||||
}
|
||||
console.log("RESULT=" + repr(beta));
|
||||
|
|
131
src/index.ts
131
src/index.ts
|
@ -3,8 +3,9 @@ import { argv, resourceUsage } from 'node:process';
|
|||
import * as tk from './tokenize.js';
|
||||
import * as util from 'util';
|
||||
import { drawEllipsePath, reduceRotation } from 'pdf-lib';
|
||||
import { isTypedArray } from 'node:util/types';
|
||||
import { isAnyArrayBuffer, isTypedArray } from 'node:util/types';
|
||||
import { error } from 'node:console';
|
||||
import { isUndefined } from 'node:util';
|
||||
|
||||
/**
|
||||
* debug reprensenting
|
||||
|
@ -42,8 +43,11 @@ function slice(x: tkTree, index?:number, end?:number): tkTree[] {
|
|||
|
||||
/**
|
||||
* TokenMatcheePair for tokens' parser combinator
|
||||
*
|
||||
* matched: the matched (now and before) tokens
|
||||
*
|
||||
* remained: tokens to be matched
|
||||
*
|
||||
* ast: abstract syntax tree
|
||||
*/
|
||||
export interface TokenMatcheePair {
|
||||
|
@ -52,6 +56,28 @@ export interface TokenMatcheePair {
|
|||
ast : tkTree[]
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a `tkTree` AST to S-expr string
|
||||
* @param t the `tkTree`
|
||||
* @returns S-expr String
|
||||
*/
|
||||
export function tkTreeToSExp(t: tkTree): string{
|
||||
var str = "";
|
||||
|
||||
if (Array.isArray(t)){
|
||||
let strArray = t.map((x)=>tkTreeToSExp(x));
|
||||
str = "(" + strArray.join(" ") + ")";
|
||||
}else{
|
||||
if (t=== undefined){
|
||||
str = "%undefined"
|
||||
}else{
|
||||
str = t.text;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description
|
||||
* match one token type.
|
||||
|
@ -94,6 +120,9 @@ export function m1TType(typ: tk.TokenType):
|
|||
* type int
|
||||
*/
|
||||
let tInt = m1TType(tk.TokenType.INT);
|
||||
let tId = m1TType(tk.TokenType.ID);
|
||||
|
||||
|
||||
let tAdd = m1TType(tk.TokenType.I_ADD);
|
||||
let tSub = m1TType(tk.TokenType.I_SUB);
|
||||
let tMul = m1TType(tk.TokenType.I_MUL);
|
||||
|
@ -143,8 +172,61 @@ function orDo(f1 : Function, f2 : Function){
|
|||
let res2 : tk.Maybe<TokenMatcheePair> = f2(x);
|
||||
return res2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param m : the `MatcheePair` to be consumed.
|
||||
* @returns if the length of `m.remained` >= 1; consumes the matchee by 1 token
|
||||
* and wraps it in `Some`,
|
||||
* otherwise, returns `None`.
|
||||
*/
|
||||
export function matchAny(m: TokenMatcheePair): tk.Maybe<TokenMatcheePair> {
|
||||
if (m.remained.length >= 1) {
|
||||
return {
|
||||
_tag: "Some", value: {
|
||||
matched: m.matched.concat(m.remained[0]),
|
||||
remained: m.remained.slice(1),
|
||||
ast : [m.remained[0]],
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return { _tag: "None" };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description repeating matching function `f`
|
||||
* zero or more times, like the asterisk `*` in regex `f*` .
|
||||
* @param f : the function to be repeated 0+ times.
|
||||
* @returns:the combined function
|
||||
*/
|
||||
export function OnceOrMoreDo(f: Function): (x: TokenMatcheePair) =>
|
||||
tk.Maybe<TokenMatcheePair> {
|
||||
return (x) => {
|
||||
var wrappedOldX: tk.Maybe<TokenMatcheePair> = { _tag: "Some", value: x };
|
||||
var wrappedNewX: tk.Maybe<TokenMatcheePair> = wrappedOldX;
|
||||
|
||||
var counter = -1;
|
||||
|
||||
while (wrappedNewX._tag != "None") {
|
||||
wrappedOldX = wrappedNewX;
|
||||
wrappedNewX = thenDo(wrappedOldX, f);
|
||||
counter += 1;
|
||||
|
||||
};
|
||||
|
||||
|
||||
if (counter <= 0){
|
||||
return { _tag: "None"};
|
||||
}
|
||||
let ast = wrappedOldX.value.ast ;
|
||||
wrappedOldX.value.ast =ast.slice(ast.length-counter);
|
||||
console.log(repr(wrappedOldX.value.ast));
|
||||
|
||||
return wrappedOldX; };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,20 +269,51 @@ let single1 = circumfix((x : TokenMatcheePair) =>
|
|||
let single2= tInt;
|
||||
let single = orDo(single1, single2);
|
||||
|
||||
/** fac1 = single "(" int ")" | single */
|
||||
/** func = single | single "(" single ")"
|
||||
* i.e.
|
||||
*
|
||||
* func = single | func_aux ( int )
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/** fac = single ["(" single ")"]? | single */
|
||||
let fac1Appliee = circumfix((x : TokenMatcheePair) => thenDo(thenDo(thenDo(tk.toSome(x), tLParen), tInt), tRParen), "fac1");
|
||||
let fac1 = (x : TokenMatcheePair) =>
|
||||
{
|
||||
let n = thenDo(thenDo(toSome(x), single), fac1Appliee);
|
||||
let raw = thenDo(thenDo(toSome(x), single), OnceOrMoreDo(fac1Appliee));
|
||||
console.log("+"+"火鳥"+"+"+repr(raw));
|
||||
|
||||
console.log("+"+"bocchitherock"+"+"+repr(n));
|
||||
|
||||
|
||||
if (raw._tag == "Some"){
|
||||
|
||||
|
||||
var result : tkTree = raw.value.ast[0];
|
||||
let applyToken : tk.Token = {text: '%apply', ln:0, col:0};
|
||||
for (var i=1; i<raw.value.ast.length; i++){
|
||||
result = [applyToken, result, raw.value.ast[i]];
|
||||
}
|
||||
|
||||
console.log("+"+"hitori"+"+"+repr(result));
|
||||
|
||||
if (!Array.isArray(result)){
|
||||
raw.value.ast = [result];
|
||||
}else{
|
||||
raw.value.ast = result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return n
|
||||
return raw;
|
||||
};
|
||||
let fac2 = single;
|
||||
let fac = orDo(fac1, fac2);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* term1 = fac (MUL | DIV) fac
|
||||
|
@ -240,7 +353,8 @@ let expr = orDo(expr1, expr2);
|
|||
|
||||
|
||||
|
||||
let tokens = tk.tokenize("12(13)(14)");
|
||||
let tokens = tk.tokenize("1");
|
||||
|
||||
//let tokens = tk.tokenize("(4-(3/4))");
|
||||
//tk.tokenize(argv[2]);
|
||||
|
||||
|
@ -259,6 +373,9 @@ let beta = expr({
|
|||
remained : tokensFiltered,
|
||||
ast : []});
|
||||
|
||||
if (beta._tag == "Some"){
|
||||
console.log(tkTreeToSExp(beta.value.ast));
|
||||
}
|
||||
|
||||
console.log("RESULT="+repr(beta));
|
||||
|
||||
|
|
Loading…
Reference in a new issue