]>
git.kianting.info Git - uann/blob - index.ts
46c4a7205501d288c574df83980d0e910e4bfd63
1 var fs
= require('fs');
2 import { argv
, resourceUsage
} from
'node:process';
3 import * as tk from
'./tokenize.js';
4 import * as util from
'util';
5 import { drawEllipsePath
, reduceRotation
} from
'pdf-lib';
6 import { isAnyArrayBuffer
, isTypedArray
} from
'node:util/types';
7 import { error
} from
'node:console';
8 import { isUndefined
} from
'node:util';
13 let repr
= (x
: any)=>{return util
.inspect(x
, {depth
: null})};
18 type tkTree
= tkTree
[] | tk
.Token
21 * concated 2 `tkTree`s
22 * @param x the array to be concated
23 * @param y the item or array to ve concated
24 * @returns concated tkTree array, or thrown error if can't be concated.
26 function concat(x
: tkTree
, y
:tkTree
): tkTree
[] {
27 if (Array.isArray(x
)){
30 throw new Error("the tkTree can't be concated, because it's not an array.");
35 function slice(x
: tkTree
, index
?:number, end
?:number): tkTree
[] {
36 if (Array.isArray(x
)){
37 return x
.slice(index
,end
);
39 throw new Error("the tkTree can't be concated, because it's not an array.");
45 * TokenMatcheePair for tokens' parser combinator
47 * matched: the matched (now and before) tokens
49 * remained: tokens to be matched
51 * ast: abstract syntax tree
53 export interface TokenMatcheePair
{
60 * convert a `tkTree` AST to S-expr string
61 * @param t the `tkTree`
62 * @returns S-expr String
64 export function tkTreeToSExp(t
: tkTree
): string{
67 if (Array.isArray(t
)){
68 let strArray
= t
.map((x
)=>tkTreeToSExp(x
));
69 str
= "(" + strArray
.join(" ") + ")";
83 * match one token type.
85 * it returns a function which test if the type of first token of the `remained` part of
86 * the argument of the function is `typ` , if it's true, update the `TokenMatcheePair` wrapped
87 * in `Some`. Otherwise, it returns `None`.
88 * * @param typ : the type to be test.
89 * @returns the updated `TokenMatcheePair` wrapped in `Some(x)` or `None`.
91 export function m1TType(typ
: tk
.TokenType
):
92 (m
: TokenMatcheePair
) => tk
.Maybe
<TokenMatcheePair
> {
93 return (m
: TokenMatcheePair
) => {
94 if (m
.remained
.length
== 0) {
95 return { _tag
: "None" };
100 const ttbm
= m
.remained
[0];
102 if (ttbm
.type == typ
) {
103 let new_matched
= m
.matched
.concat(ttbm
);
104 let result
: tk
.Some
<TokenMatcheePair
> = {
105 _tag
: "Some", value
: {
106 matched
: new_matched
,
107 remained
: m
.remained
.slice(1),
114 return { _tag
: "None" };
122 let tInt
= m1TType(tk
.TokenType
.INT
);
123 let tId
= m1TType(tk
.TokenType
.ID
);
126 let tAdd
= m1TType(tk
.TokenType
.I_ADD
);
127 let tSub
= m1TType(tk
.TokenType
.I_SUB
);
128 let tMul
= m1TType(tk
.TokenType
.I_MUL
);
129 let tDiv
= m1TType(tk
.TokenType
.I_DIV
);
130 let tLParen
= m1TType(tk
.TokenType
.L_PAREN
);
131 let tRParen
= m1TType(tk
.TokenType
.R_PAREN
);
132 let tComma
= m1TType(tk
.TokenType
.COMMA
);
133 let toSome
= tk
.toSome
;
136 argv
.forEach((val
, index
) => {
137 console
.log(`${index}=${val}`);
142 * like `m ==> f` in ocaml
143 * @param m matchee wrapped
144 * @param f matching function
145 * @returns wrapped result
147 function thenDo(m
: tk
.Maybe
<TokenMatcheePair
>, f
: Function){
148 if (m
._tag
== "None"){
151 var a
: tk
.Maybe
<TokenMatcheePair
> = f(m
.value
);
152 if (a
._tag
== "Some"){
153 a
.value
.ast
= concat(m
.value
.ast
, a
.value
.ast
);
161 * like `f1 | f2` in regex
162 * @param f1 the first tried function
163 * @param f2 the second tried function
164 * @returns wrapped result
166 function orDo(f1
: Function, f2
: Function){
167 return (x
: TokenMatcheePair
) =>{
168 let res1
: tk
.Maybe
<TokenMatcheePair
> = f1(x
);
169 if (res1
._tag
== "Some"){
172 let res2
: tk
.Maybe
<TokenMatcheePair
> = f2(x
);
181 * @param m : the `MatcheePair` to be consumed.
182 * @returns if the length of `m.remained` >= 1; consumes the matchee by 1 token
183 * and wraps it in `Some`,
184 * otherwise, returns `None`.
186 export function matchAny(m
: TokenMatcheePair
): tk
.Maybe
<TokenMatcheePair
> {
187 if (m
.remained
.length
>= 1) {
189 _tag
: "Some", value
: {
190 matched
: m
.matched
.concat(m
.remained
[0]),
191 remained
: m
.remained
.slice(1),
192 ast
: [m
.remained
[0]],
196 return { _tag
: "None" };
201 * Danger : Maybe it's not enough to work.
202 * @description repeating matching function `f`
203 * zero or more times, like the asterisk `*` in regex `f*` .
204 * @param f : the function to be repeated 0+ times.
205 * @returns:the combined function
207 export function OnceOrMoreDo(f
: Function): (x
: TokenMatcheePair
) =>
208 tk
.Maybe
<TokenMatcheePair
> {
210 var wrappedOldX
: tk
.Maybe
<TokenMatcheePair
> = { _tag
: "Some", value
: x
};
211 var wrappedNewX
: tk
.Maybe
<TokenMatcheePair
> = wrappedOldX
;
215 while (wrappedNewX
._tag
!= "None") {
216 wrappedOldX
= wrappedNewX
;
217 wrappedNewX
= thenDo(wrappedOldX
, f
);
223 return { _tag
: "None"};
225 let ast
= wrappedOldX
.value
.ast
;
226 wrappedOldX
.value
.ast
=ast
.slice(ast
.length
-counter
);
227 console
.log(repr(wrappedOldX
.value
.ast
));
229 return wrappedOldX
; };
233 * aux function for midfix operator
235 * @param signal the rule name
238 let midfix
= (f
: Function, signal
? : string) => (x
: TokenMatcheePair
)=>{
240 if (a
._tag
== "Some"){
241 let ast_tail
: tkTree
[] = slice(a
.value
.ast
,a
.value
.ast
.length
-3);
242 let new_ast
= [ast_tail
];
243 a
.value
.ast
= new_ast
;
245 // console.log("+"+signal+"+"+repr(a));
252 let circumfix
= (f
: Function, signal
? : string) => (x
: TokenMatcheePair
)=>{
253 var a
: tk
.Maybe
<TokenMatcheePair
> = f(x
);
254 if (a
._tag
== "Some"){
255 console
.log("$$$"+repr(a
.value
.ast
));
256 let inner
= a
.value
.ast
[a
.value
.ast
.length
-2];
257 var ast_middle
: tkTree
[];
258 // the list should not be (%list) (%apply) (%lambda) etc.
259 if (Array.isArray(inner
)){
260 if ('text' in inner
[0] && (inner
[0].text
.slice(0,1) != "%")){
264 ast_middle
= [inner
];
268 ast_middle
= [inner
];
270 let new_ast
= [ast_middle
];
271 a
.value
.ast
= new_ast
;
276 /** single1 = tInt | "(" expr ")"*/
277 let single1
= circumfix((x
: TokenMatcheePair
) =>
278 thenDo(thenDo(thenDo(toSome(x
), tLParen
), expr
), tRParen
), "fac1");
280 let single
= orDo(single1
, single2
);
282 /** args = single "," args | single */
283 let args1
= (x
: TokenMatcheePair
)=>{
284 var ret
= thenDo(thenDo(thenDo(toSome(x
), single
), tComma
), args
);
285 if (ret
._tag
== "Some"){
286 let retLength
= ret
.value
.ast
.length
;
287 ret
.value
.ast
= [[ret
.value
.ast
[retLength
-3]].concat(ret
.value
.ast
[retLength
-1])];
288 console
.log("$$"+repr(ret
.value
.ast
));
295 let args
= orDo(args1
, args2
);
298 /** callees = "(" args ")" | "(" ")" */
301 let callees1
= circumfix((x
: TokenMatcheePair
) =>
302 thenDo(thenDo(thenDo(toSome(x
), tLParen
), args
), tRParen
), "callees1");
303 let callees2
= (x
: TokenMatcheePair
)=>{
304 let ret
= thenDo(thenDo(toSome(x
), tLParen
), tRParen
);
305 if (ret
._tag
== "Some"){
306 let new_ast
: tkTree
[] = [[]];
307 ret
.value
.ast
= new_ast
;
312 let callees
= orDo(callees1
, callees2
);
316 /** %apply R combinating token */
319 type: tk
.TokenType
.ID
,
324 /** facAux = callees facAux | callees */
325 let facAux1
= (x
: TokenMatcheePair
)=>{
326 var ret
= thenDo(thenDo(toSome(x
), callees
), facAux
);
327 if (ret
._tag
== "Some"){
328 console
.log("1232345"+repr(tkTreeToSExp(ret
.value
.ast
[ret
.value
.ast
.length
-1])));
329 let last1
= ret
.value
.ast
[ret
.value
.ast
.length
-1];
330 let last2
= ret
.value
.ast
[ret
.value
.ast
.length
-2];
333 let b
: tkTree
[] = [applyToken
];
334 ret
.value
.ast
= [b
.concat([last2
, last1
])];
335 console
.log("11111"+repr(tkTreeToSExp(ret
.value
.ast
)));
340 let facAux2
= callees
;
341 let facAux
= orDo(facAux1
, facAux2
);
345 /** fac = single facAux | single
346 * Issue1 to be fixed.
348 let fac1
= (x
: TokenMatcheePair
)=>{
349 var ret
= thenDo(thenDo(toSome(x
), single
),facAux
);
350 if(ret
._tag
== "Some"){
351 console
.log("777"+repr(tkTreeToSExp(ret
.value
.ast
)));
352 ret
.value
.ast
= [applyToken
, ret
.value
.ast
[ret
.value
.ast
.length
-2],
353 ret
.value
.ast
[ret
.value
.ast
.length
-1]];
355 rearrangeTree(ret
.value
.ast
);
356 console
.log("888"+repr(tkTreeToSExp(ret
.value
.ast
)));
362 let fac
= orDo(fac1
, fac2
);
366 * rearrangeTree : for applyToken subtree from right-combination to
369 * @return another ast
371 function rearrangeTree(x
: any) : any {
373 if (x
!== undefined){
374 for (var i
=1;i
<x
.length
;i
++){
377 console
.log("@@"+repr(x
[0]));
379 if (x
[0] == applyToken
){
380 if (Array.isArray(x
[2]) && x
[2][0] == applyToken
){
381 let rl
= rearrangeTree(x
[2][1]);
382 let rr
= rearrangeTree(x
[2][2]);
383 let l
= rearrangeTree(x
[1]);
385 x
[1] = [applyToken
, l
, rl
];
387 console
.log("@@=="+repr(x
));
393 x
[1] = rearrangeTree(x
[1]);
394 x
[2] = rearrangeTree(x
[2]);
395 console
.log("@@=="+repr(x
));
411 * term1 = fac (MUL | DIV) fac
414 let term1
= midfix((x
: TokenMatcheePair
)=>
415 thenDo(thenDo(thenDo(toSome(x
), fac
), orDo(tMul
,tDiv
)), fac
), "term1");
420 * term2 = int MUL int
425 * term = term1 | term2
427 let term
= orDo(term1
, term2
);
432 * expr1 = term ADD term
434 let expr1
= midfix((x
: TokenMatcheePair
)=>
435 thenDo(thenDo(thenDo(toSome(x
), term
), orDo(tAdd
,tSub
)), term
), "expr1");
442 * expr = expr1 | expr2
444 let expr
= orDo(expr1
, expr2
);
448 let tokens
= tk
.tokenize("1");
449 let tokens2
= tk
.tokenize("1(2)");
450 let tokens3
= tk
.tokenize("1(2)(3)");
451 let tokens4
= tk
.tokenize("2()(4)(5,6)(7,8,9,10)");
453 //let tokens = tk.tokenize("(4-(3/4))");
454 //tk.tokenize(argv[2]);
456 let tokensFiltered
= tokens4
.filter(
457 (x
)=>{return (x
.type != tk
.TokenType
.NL
458 && x
.type != tk
.TokenType
.SP
)});
464 remained
: tokensFiltered
,
469 if (beta
._tag
== "Some"){
470 beta
.value
.ast
= rearrangeTree(beta
.value
.ast
);
471 console
.log(tkTreeToSExp(beta
.value
.ast
));
475 console
.log("RESULT="+repr(beta
));