]>
git.kianting.info Git - uann/blob - index.ts
0d94c74c6fb2434f783f1451c0b86f3824973a80
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 { isTypedArray
} from
'node:util/types';
7 import { error
} from
'node:console';
12 let repr
= (x
: any)=>{return util
.inspect(x
, {depth
: null})};
17 type tkTree
= tkTree
[] | tk
.Token
20 * concated 2 `tkTree`s
21 * @param x the array to be concated
22 * @param y the item or array to ve concated
23 * @returns concated tkTree array, or thrown error if can't be concated.
25 function concat(x
: tkTree
, y
:tkTree
): tkTree
[] {
26 if (Array.isArray(x
)){
29 throw new Error("the tkTree can't be concated, because it's not an array.");
34 function slice(x
: tkTree
, index
?:number, end
?:number): tkTree
[] {
35 if (Array.isArray(x
)){
36 return x
.slice(index
,end
);
38 throw new Error("the tkTree can't be concated, because it's not an array.");
44 * TokenMatcheePair for tokens' parser combinator
45 * matched: the matched (now and before) tokens
46 * remained: tokens to be matched
47 * ast: abstract syntax tree
49 export interface TokenMatcheePair
{
57 * match one token type.
59 * it returns a function which test if the type of first token of the `remained` part of
60 * the argument of the function is `typ` , if it's true, update the `TokenMatcheePair` wrapped
61 * in `Some`. Otherwise, it returns `None`.
62 * * @param typ : the type to be test.
63 * @returns the updated `TokenMatcheePair` wrapped in `Some(x)` or `None`.
65 export function m1TType(typ
: tk
.TokenType
):
66 (m
: TokenMatcheePair
) => tk
.Maybe
<TokenMatcheePair
> {
67 return (m
: TokenMatcheePair
) => {
68 if (m
.remained
.length
== 0) {
69 return { _tag
: "None" };
74 const ttbm
= m
.remained
[0];
76 if (ttbm
.type == typ
) {
77 let new_matched
= m
.matched
.concat(ttbm
);
78 let result
: tk
.Some
<TokenMatcheePair
> = {
79 _tag
: "Some", value
: {
81 remained
: m
.remained
.slice(1),
88 return { _tag
: "None" };
96 let tInt
= m1TType(tk
.TokenType
.INT
);
97 let tAdd
= m1TType(tk
.TokenType
.I_ADD
);
98 let tSub
= m1TType(tk
.TokenType
.I_SUB
);
99 let tMul
= m1TType(tk
.TokenType
.I_MUL
);
100 let tDiv
= m1TType(tk
.TokenType
.I_DIV
);
101 let tLParen
= m1TType(tk
.TokenType
.L_PAREN
);
102 let tRParen
= m1TType(tk
.TokenType
.R_PAREN
);
104 let toSome
= tk
.toSome
;
107 argv
.forEach((val
, index
) => {
108 console
.log(`${index}=${val}`);
113 * like `m ==> f` in ocaml
114 * @param m matchee wrapped
115 * @param f matching function
116 * @returns wrapped result
118 function thenDo(m
: tk
.Maybe
<TokenMatcheePair
>, f
: Function){
119 if (m
._tag
== "None"){
122 var a
: tk
.Maybe
<TokenMatcheePair
> = f(m
.value
);
123 if (a
._tag
== "Some"){
124 a
.value
.ast
= concat(m
.value
.ast
, a
.value
.ast
);
132 * like `f1 | f2` in regex
133 * @param f1 the first tried function
134 * @param f2 the second tried function
135 * @returns wrapped result
137 function orDo(f1
: Function, f2
: Function){
138 return (x
: TokenMatcheePair
) =>{
139 let res1
: tk
.Maybe
<TokenMatcheePair
> = f1(x
);
140 if (res1
._tag
== "Some"){
143 let res2
: tk
.Maybe
<TokenMatcheePair
> = f2(x
);
151 * aux function for midfix operator
153 * @param signal the rule name
156 let midfix
= (f
: Function, signal
? : string) => (x
: TokenMatcheePair
)=>{
158 if (a
._tag
== "Some"){
159 let ast_tail
: tkTree
[] = slice(a
.value
.ast
,a
.value
.ast
.length
-3);
160 let new_ast
= [ast_tail
];
161 a
.value
.ast
= new_ast
;
163 console
.log("+"+signal
+"+"+repr(a
));
170 let circumfix
= (f
: Function, signal
? : string) => (x
: TokenMatcheePair
)=>{
172 if (a
._tag
== "Some"){
173 let inner
= a
.value
.ast
[a
.value
.ast
.length
-2];
174 let ast_middle
: tkTree
[] = [inner
];
175 let new_ast
= [ast_middle
];
176 a
.value
.ast
= new_ast
;
182 * TODO: 12(13)(14) only parsed with only 12(13)
184 /** single1 = tInt | "(" expr ")"*/
185 let single1
= circumfix((x
: TokenMatcheePair
) =>
186 thenDo(thenDo(thenDo(tk
.toSome(x
), tLParen
), expr
), tRParen
), "fac1");
188 let single
= orDo(single1
, single2
);
190 /** fac1 = single "(" int ")" | single */
191 let fac1Appliee
= circumfix((x
: TokenMatcheePair
) => thenDo(thenDo(thenDo(tk
.toSome(x
), tLParen
), tInt
), tRParen
), "fac1");
192 let fac1
= (x
: TokenMatcheePair
) =>
194 let n
= thenDo(thenDo(toSome(x
), single
), fac1Appliee
);
196 console
.log("+"+"bocchitherock"+"+"+repr(n
));
201 let fac
= orDo(fac1
, fac2
);
206 * term1 = fac (MUL | DIV) fac
209 let term1
= midfix((x
: TokenMatcheePair
)=>
210 thenDo(thenDo(thenDo(tk
.toSome(x
), fac
), orDo(tMul
,tDiv
)), fac
), "term1");
215 * term2 = int MUL int
220 * term = term1 | term2
222 let term
= orDo(term1
, term2
);
227 * expr1 = term ADD term
229 let expr1
= midfix((x
: TokenMatcheePair
)=>
230 thenDo(thenDo(thenDo(tk
.toSome(x
), term
), orDo(tAdd
,tSub
)), term
), "expr1");
237 * expr = expr1 | expr2
239 let expr
= orDo(expr1
, expr2
);
243 let tokens
= tk
.tokenize("12(13)(14)");
244 //let tokens = tk.tokenize("(4-(3/4))");
245 //tk.tokenize(argv[2]);
247 let tokensFiltered
= tokens
.filter(
248 (x
)=>{return (x
.type != tk
.TokenType
.NL
249 && x
.type != tk
.TokenType
.SP
)});
251 let wrappedTokens
: tk
.Maybe
<TokenMatcheePair
> =
254 remained
: tokensFiltered
,
259 remained
: tokensFiltered
,
263 console
.log("RESULT="+repr(beta
));