]> git.kianting.info Git - clo/blob - src/index.ts
add rule and find some issue
[clo] / src / index.ts
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';
8
9 /**
10 * debug reprensenting
11 */
12 let repr = (x : any)=>{return util.inspect(x, {depth: null})};
13
14 /**
15 * token tree type.
16 */
17 type tkTree = tkTree[] | tk.Token
18
19 /**
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.
24 */
25 function concat(x: tkTree, y:tkTree): tkTree[] {
26 if (Array.isArray(x)){
27 return x.concat(y);
28 }else{
29 throw new Error("the tkTree can't be concated, because it's not an array.");
30
31 }
32 }
33
34 function slice(x: tkTree, index?:number, end?:number): tkTree[] {
35 if (Array.isArray(x)){
36 return x.slice(index,end);
37 }else{
38 throw new Error("the tkTree can't be concated, because it's not an array.");
39
40 }
41 }
42
43 /**
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
48 */
49 export interface TokenMatcheePair {
50 matched: tk.Token[]
51 remained: tk.Token[]
52 ast : tkTree[]
53 }
54
55 /**
56 * @description
57 * match one token type.
58 *
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`.
64 */
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" };
70 }
71 /**
72 * token to be matched
73 * */
74 const ttbm = m.remained[0];
75
76 if (ttbm.type == typ) {
77 let new_matched = m.matched.concat(ttbm);
78 let result : tk.Some<TokenMatcheePair> = {
79 _tag: "Some", value: {
80 matched: new_matched,
81 remained: m.remained.slice(1),
82 ast: ([ttbm]),
83 }
84 };
85 return result;
86 }
87 else {
88 return { _tag: "None" };
89 }
90 }
91 };
92
93 /**
94 * type int
95 */
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);
103
104 let toSome = tk.toSome;
105
106
107 argv.forEach((val, index) => {
108 console.log(`${index}=${val}`);
109 });
110
111
112 /**
113 * like `m ==> f` in ocaml
114 * @param m matchee wrapped
115 * @param f matching function
116 * @returns wrapped result
117 */
118 function thenDo(m : tk.Maybe<TokenMatcheePair>, f : Function){
119 if (m._tag == "None"){
120 return m;
121 }else{
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);
125 }
126
127 return a;
128 }
129 }
130
131 /**
132 * like `f1 | f2` in regex
133 * @param f1 the first tried function
134 * @param f2 the second tried function
135 * @returns wrapped result
136 */
137 function orDo(f1 : Function, f2 : Function){
138 return (x : TokenMatcheePair) =>{
139 let res1 : tk.Maybe<TokenMatcheePair> = f1(x);
140 if (res1._tag == "Some"){
141 return res1;
142 }else{
143 let res2 : tk.Maybe<TokenMatcheePair> = f2(x);
144 return res2;
145 }
146 }
147
148 }
149
150 /**
151 * aux function for midfix operator
152 * @param f function
153 * @param signal the rule name
154 * @returns
155 */
156 let midfix = (f : Function, signal? : string) => (x : TokenMatcheePair)=>{
157 var a = f(x);
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;
162
163 console.log("+"+signal+"+"+repr(a));
164
165
166 }
167 return a;
168 }
169
170 let circumfix = (f : Function, signal? : string) => (x : TokenMatcheePair)=>{
171 var a = f(x);
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;
177 }
178 return a;
179 }
180
181 /**
182 * TODO: 12(13)(14) only parsed with only 12(13)
183 */
184 /** single1 = tInt | "(" expr ")"*/
185 let single1 = circumfix((x : TokenMatcheePair) =>
186 thenDo(thenDo(thenDo(tk.toSome(x), tLParen), expr), tRParen), "fac1");
187 let single2= tInt;
188 let single = orDo(single1, single2);
189
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) =>
193 {
194 let n = thenDo(thenDo(toSome(x), single), fac1Appliee);
195
196 console.log("+"+"bocchitherock"+"+"+repr(n));
197
198 return n
199 };
200 let fac2 = single;
201 let fac = orDo(fac1, fac2);
202
203
204 /**
205 *
206 * term1 = fac (MUL | DIV) fac
207 */
208
209 let term1 = midfix((x : TokenMatcheePair)=>
210 thenDo(thenDo(thenDo(tk.toSome(x), fac), orDo(tMul,tDiv)), fac), "term1");
211
212
213 /**
214 *
215 * term2 = int MUL int
216 */
217 let term2 = fac;
218
219 /**
220 * term = term1 | term2
221 */
222 let term = orDo(term1, term2);
223
224
225 /**
226 *
227 * expr1 = term ADD term
228 */
229 let expr1 = midfix((x : TokenMatcheePair)=>
230 thenDo(thenDo(thenDo(tk.toSome(x), term), orDo(tAdd,tSub)), term), "expr1");
231 /**
232 * expr2 = term
233 */
234 let expr2 = term;
235
236 /**
237 * expr = expr1 | expr2
238 */
239 let expr = orDo(expr1, expr2);
240
241
242
243 let tokens = tk.tokenize("12(13)(14)");
244 //let tokens = tk.tokenize("(4-(3/4))");
245 //tk.tokenize(argv[2]);
246
247 let tokensFiltered = tokens.filter(
248 (x)=>{return (x.type != tk.TokenType.NL
249 && x.type != tk.TokenType.SP)});
250
251 let wrappedTokens : tk.Maybe<TokenMatcheePair> =
252 tk.toSome({
253 matched : [] ,
254 remained : tokensFiltered,
255 ast : []});
256
257 let beta = expr({
258 matched : [] ,
259 remained : tokensFiltered,
260 ast : []});
261
262
263 console.log("RESULT="+repr(beta));
264