]>
git.kianting.info Git - uann/blob - index.js
efa8b6854087eff3ca3b68153f1a575b614d0dba
2 Object
.defineProperty(exports
, "__esModule", { value
: true });
3 exports
.tokenize
= exports
.zeroOrOnceDo
= exports
.notDo
= exports
.zeroOrMoreDo
= exports
.orDo
= exports
.thenDo
= exports
.charToCodepoint
= exports
.matchRange
= exports
.matchAny
= exports
.match1Char
= exports
.TokenType
= void 0;
4 var fs
= require('fs');
6 * wrap a x in a `Some(T)`
7 * @param x : variable to be wrapped.
8 * @returns wrapped `x`.
11 return { _tag
: "Some", value
: x
};
17 * SP, // half-width space and tab
23 * OP, // operator or something like it
30 (function (TokenType
) {
31 TokenType
[TokenType
["NL"] = 0] = "NL";
32 TokenType
[TokenType
["SP"] = 1] = "SP";
33 TokenType
[TokenType
["ID"] = 2] = "ID";
34 TokenType
[TokenType
["STR"] = 3] = "STR";
35 TokenType
[TokenType
["OP"] = 4] = "OP";
36 TokenType
[TokenType
["FLO"] = 5] = "FLO";
37 TokenType
[TokenType
["INT"] = 6] = "INT";
38 })(TokenType
|| (exports
.TokenType
= TokenType
= {}));
41 * it returns a function which test if the first char of the `remained` part of
42 * the argument of the function is `c`, if it's true, update the `MatchedPair` wrapped
43 * in `Some`. Otherwise, it returns `None`.
44 * * @param c : the char to be test.
45 * @returns the updated `MatchedPair` wrapped in `Some(x)` or `None`.
47 function match1Char(c
) {
49 if (m
.remained
.length
== 0) {
50 return { _tag
: "None" };
52 const charToBeMatched
= m
.remained
[0];
53 if (charToBeMatched
=== c
) {
54 return { _tag
: "Some", value
: {
55 matched
: m
.matched
+ charToBeMatched
,
56 remained
: m
.remained
.substring(1)
60 return { _tag
: "None" };
64 exports
.match1Char
= match1Char
;
68 * @param m : the `MatcheePair` to be consumed.
69 * @returns if the length of `m.remained` >= 1; consumes the matchee by 1 char and wraps it in `Some`,
70 * otherwise, returns `None`.
72 function matchAny(m
) {
73 if (m
.remained
.length
>= 1) {
74 return { _tag
: "Some", value
: {
75 matched
: m
.matched
+ m
.remained
[0],
76 remained
: m
.remained
.substring(1)
80 return { _tag
: "None" };
83 exports
.matchAny
= matchAny
;
86 * it returns a function which test if the first char of the `remained` part of
87 * the argument of the function is between `l` and `u`, if it's true, update the `MatchedPair` wrapped
88 * in `Some`. Otherwise, it returns `None`.
89 * * @param l : lower bound char, 1-char string
90 * * @param u : upper bound char, 1-char string
91 * @returns the updated `MatchedPair` wrapped in `Some(x)` or `None`.
93 function matchRange(l
, u
) {
94 let lCodepoint
= charToCodepoint(l
);
95 let uCodepoint
= charToCodepoint(u
);
97 throw new Error("Error: the codepoint of `" + l
+ "` is not smaller than `" + u
+ "`)");
100 if (m
.remained
.length
< 1) {
101 return { _tag
: "None" };
103 const charToBeMatched
= m
.remained
[0];
104 const codePointToBeMatched
= charToCodepoint(charToBeMatched
);
105 if (codePointToBeMatched
>= lCodepoint
&& codePointToBeMatched
<= uCodepoint
) {
106 return { _tag
: "Some", value
: {
107 matched
: m
.matched
+ charToBeMatched
,
108 remained
: m
.remained
.substring(1)
112 return { _tag
: "None" };
116 exports
.matchRange
= matchRange
;
119 * convert the one-char string to codepoint.
120 * @param s : the string to code point.
121 * @returns if `s.length > 1` return error; otherwise, return the codepoint of `s`.
123 function charToCodepoint(s
) {
125 throw new Error("Error: the length of input string for " + s
+ "is " + s
.length
+ `,
126 however, it should be 1.`);
129 return s
.charCodeAt(0);
132 exports
.charToCodepoint
= charToCodepoint
;
134 * @description thendo(input, f, ...) like
136 * @param input: the wrapped input.
137 * @param f: the function to be applied.
139 * @returns:the applied wrapped result `MatcheePair`.
141 function thenDo(input
, f
) {
142 if (input
._tag
== "None") {
146 let inner
= input
.value
;
150 exports
.thenDo
= thenDo
;
152 * @description "or", like the regex `( f1 | f2 )` .
153 * It returns a function `f` of which the argument is`x`.
154 * if `f1(x)` is None, then `f` returns `f2(x)`. Otherwise,
155 * `F` returns `f1(x)`.
156 * @param f1 : 1st function to be compared
157 * @param f2 : 2nd function to be compared
158 * @returns:the combined function
160 function orDo(f1
, f2
) {
164 if (f1x
._tag
== "None") {
175 * @description repeating matching function `f`
176 * zero or more times, like the asterisk `*` in regex `f*` .
177 * @param f : the function to be repeated 0+ times.
178 * @returns:the combined function
180 function zeroOrMoreDo(f
) {
182 var wrapped_old_x
= { _tag
: "Some", value
: x
};
183 var wrapped_new_x
= wrapped_old_x
;
184 while (wrapped_new_x
._tag
!= "None") {
185 wrapped_old_x
= wrapped_new_x
;
186 wrapped_new_x
= thenDo(wrapped_old_x
, f
);
189 return wrapped_old_x
;
192 exports
.zeroOrMoreDo
= zeroOrMoreDo
;
194 * @description Not. like the `^` inside regex of [^f].
195 * returns a function `F(x)` such that if `f(x)` is `None`,
196 * returns the x consuming a char; if `f(x)` is not None, F(x)
198 * @param f: the function forbidden to be matched.
199 * @returns: combined function `F`.
207 let f_x
= thenDo(wrapped_x
, f
);
208 if (f_x
._tag
!= "None") {
209 return { _tag
: "None" };
212 return thenDo(wrapped_x
, matchAny
);
216 exports
.notDo
= notDo
;
218 * if `x` is matched by `f` once, returns `f(x)`. Otherwise,
220 * similar to `?` in regex `f?`.
221 * @param f : the function to be matched
222 * @returns return wrapped f(x)
224 function zeroOrOnceDo(f
) {
226 var wrapped_old_x
= { _tag
: "Some", value
: x
};
227 var wrapped_new_x
= thenDo(wrapped_old_x
, f
);
228 if (wrapped_new_x
._tag
!= "None") {
229 return wrapped_new_x
;
232 return wrapped_old_x
;
236 exports
.zeroOrOnceDo
= zeroOrOnceDo
;
237 function tokenize(input
) {
238 var input_matchee_pair
= toSome({ matched
: "",
240 // integer = ([+]|[-])?\d\d*
241 let integer
= (x
) => {
242 let wrapped_x
= toSome(x
);
243 let plusMinus
= orDo(match1Char('+'), match1Char('-')); // ([+]|[-])
244 let d
= matchRange('0', '9'); // \d
245 var result
= thenDo(thenDo(thenDo(wrapped_x
, zeroOrOnceDo(plusMinus
)), d
), zeroOrMoreDo(d
));
246 if (result
._tag
== "Some") {
247 result
.value
.matched_type
= TokenType
.INT
;
252 let wrapped_x
= toSome(x
);
253 let s_aux
= orDo(match1Char(' '), match1Char('\t')); // (" " | "\t")
254 var result
= thenDo(thenDo(wrapped_x
, s_aux
), zeroOrMoreDo(s_aux
));
255 if (result
._tag
== "Some") {
256 result
.value
.matched_type
= TokenType
.SP
;
260 let newline
= (x
) => {
261 let wrapped_x
= toSome(x
);
263 let result
= thenDo(thenDo(wrapped_x
, zeroOrOnceDo(match1Char('\r'))), match1Char('\n'));
264 if (result
._tag
== "Some") {
265 result
.value
.matched_type
= TokenType
.NL
;
269 let term
= (token_list
, x
) => {
273 let term_list
= [newline
, space
, integer
];
274 let term_aux
= term_list
.reduce((x
, y
) => orDo(x
, y
));
275 var new_x
= thenDo(old_x
, term_aux
);
276 while (new_x
._tag
!= "None") {
277 if (new_x
.value
.matched_type
!= TokenType
.NL
) {
278 col
+= new_x
.value
.matched
.length
;
279 token_list
.push({ text
: new_x
.value
.matched
,
280 type
: new_x
.value
.matched_type
,
287 token_list
.push({ text
: new_x
.value
.matched
,
288 type
: new_x
.value
.matched_type
,
292 old_x
= toSome({ matched
: "",
293 remained
: new_x
.value
.remained
});
294 new_x
= thenDo(old_x
, term_aux
);
296 if (old_x
.value
.remained
.length
) {
297 console
.log(token_list
);
298 throw new Error("the code can't be tokenized is near Ln. " + ln
+ ", Col." + col
299 + ", starting with " + old_x
.value
.remained
.substring(0, 10));
303 console
.log(term([], input_matchee_pair
));
304 // TODO: id, string, space, basic operator, 3 marks: @, {, }.
306 exports
.tokenize
= tokenize
;