]>
git.kianting.info Git - uann/blob - src/index.ts
8cbd145671c4508ca55759035ba2da57c1edcccb
1 var fs
= require('fs');
3 export type Some
<T
> = { _tag
: "Some"; value
: T
};
4 export type None
= {_tag
: "None"};
8 * wrap a x in a `Some(T)`
9 * @param x : variable to be wrapped.
10 * @returns wrapped `x`.
12 function toSome
<T
>(x
: T
): Some
<T
>{
13 return { _tag
: "Some", value
: x
};
16 * @description Like the `Some(a)` and `None` in Rust.
20 * let exam1 : Maybe<Number> = { _tag: "Some", value: 12 };
21 * let exam2 : Maybe<Number> = None;
24 export type Maybe
<T
> = Some
<T
> | None
;
29 * the pair of the string to be matched later and the string that have been matched
31 export interface MatcheePair
{
32 /** have been matched */
34 /** will be tested whether it'll be matched. */
40 * it returns a function which test if the first char of the `remained` part of
41 * the argument of the function is `c`, if it's true, update the `MatchedPair` wrapped
42 * in `Some`. Otherwise, it returns `None`.
43 * * @param c : the char to be test.
44 * @returns the updated `MatchedPair` wrapped in `Some(x)` or `None`.
46 export function match1Char(c
: string) : (m
: MatcheePair
) => Maybe
<MatcheePair
> {
47 return (m
: MatcheePair
)=>{
48 if (m
.remained
.length
== 0){
49 return { _tag
: "None" };
51 const charToBeMatched
= m
.remained
[0];
52 if (charToBeMatched
=== c
){
53 return {_tag
: "Some", value
:{
54 matched
: m
.matched
+ charToBeMatched
,
55 remained
: m
.remained
.substring(1)}};
58 return {_tag
: "None"};
65 * @param m : the `MatcheePair` to be consumed.
66 * @returns if the length of `m.remained` >= 1; consumes the matchee by 1 char and wraps it in `Some`,
67 * otherwise, returns `None`.
69 export function matchAny(m
: MatcheePair
) : Maybe
<MatcheePair
>{
70 if (m
.remained
.length
>= 1){
71 return {_tag
: "Some", value
:{
72 matched
: m
.matched
+ m
.remained
[0],
73 remained
: m
.remained
.substring(1)}};
75 return {_tag
: "None"};
81 * it returns a function which test if the first char of the `remained` part of
82 * the argument of the function is between `l` and `u`, if it's true, update the `MatchedPair` wrapped
83 * in `Some`. Otherwise, it returns `None`.
84 * * @param l : lower bound char, 1-char string
85 * * @param u : upper bound char, 1-char string
86 * @returns the updated `MatchedPair` wrapped in `Some(x)` or `None`.
88 export function matchRange(l
: string, u
: string) : (m
: MatcheePair
) => Maybe
<MatcheePair
> {
89 let lCodepoint
= charToCodepoint(l
);
90 let uCodepoint
= charToCodepoint(u
);
92 throw new Error("Error: the codepoint of `"+l
+"` is not smaller than `"+u
+"`)");
94 return (m
: MatcheePair
)=>{
95 if (m
.remained
.length
< 1){
96 return {_tag
: "None"};
98 const charToBeMatched
= m
.remained
[0];
99 const codePointToBeMatched
= charToCodepoint(charToBeMatched
);
100 if (codePointToBeMatched
>= lCodepoint
&& codePointToBeMatched
<= uCodepoint
){
101 return {_tag
: "Some", value
:{
102 matched
: m
.matched
+ charToBeMatched
,
103 remained
: m
.remained
.substring(1)}};
106 return {_tag
: "None"};
112 * convert the one-char string to codepoint.
113 * @param s : the string to code point.
114 * @returns if `s.length > 1` return error; otherwise, return the codepoint of `s`.
116 export function charToCodepoint(s
: string): number{
118 throw new Error("Error: the length of input string for "+s
+ "is "+s
.length
+`,
119 however, it should be 1.`);
121 return s
.charCodeAt(0);
126 * @description thendo(input, f, ...) like
128 * @param input: the wrapped input.
129 * @param f: the function to be applied.
131 * @returns:the applied wrapped result `MatcheePair`.
133 export function thenDo
<T
>(input
: Maybe
<T
>, f
: Function) : Maybe
<T
>{
134 if (input
._tag
== "None"){
138 let inner
= input
.value
;
144 * @description "or", like the regex `( f1 | f2 )` .
145 * It returns a function `f` of which the argument is`x`.
146 * if `f1(x)` is None, then `f` returns `f2(x)`. Otherwise,
147 * `F` returns `f1(x)`.
148 * @param f1 : 1st function to be compared
149 * @param f2 : 2nd function to be compared
150 * @returns:the combined function
152 export function orDo
<T
>(f1
: Function, f2
: Function) : (x
: T
) => Maybe
<T
>{
154 let f1x
: Maybe
<T
> = (f1(x
));
156 if (f1x
._tag
== "None"){
168 * @description repeating matching function `f`
169 * zero or more times, like the asterisk `*` in regex `f*` .
170 * @param f : the function to be repeated 0+ times.
171 * @returns:the combined function
173 export function zeroOrMoreDo
<T
>(f
: Function): (x
: T
) => Maybe
<T
>{
175 var wrapped_old_x
: Maybe
<T
> = {_tag
: "Some", value
: x
};
176 var wrapped_new_x
: Maybe
<T
> = wrapped_old_x
;
178 while (wrapped_new_x
._tag
!= "None"){
179 wrapped_old_x
= wrapped_new_x
;
180 wrapped_new_x
= thenDo(wrapped_old_x
, f
);
183 return wrapped_old_x
;
188 * @description Not. like the `^` inside regex of [^f].
189 * returns a function `F(x)` such that if `f(x)` is `None`,
190 * returns the x consuming a char; if `f(x)` is not None, F(x)
192 * @param f: the function forbidden to be matched.
193 * @returns: combined function `F`.
195 export function notDo
<T
>(f
: Function): (x
: T
) => Maybe
<T
>{
197 let wrapped_x
: Maybe
<T
> = {
201 let f_x
= thenDo(wrapped_x
, f
);
203 if (f_x
._tag
!= "None"){
204 return {_tag
:"None"};
206 return thenDo(wrapped_x
, matchAny
);
212 * if `x` is matched by `f` once, returns `f(x)`. Otherwise,
214 * similar to `?` in regex `f?`.
215 * @param f : the function to be matched
216 * @returns return wrapped f(x)
218 export function zeroOrOnceDo
<T
>(f
: Function): (x
: T
) => Maybe
<T
>{
220 var wrapped_old_x
: Maybe
<T
> = {_tag
: "Some", value
: x
};
221 var wrapped_new_x
= thenDo(wrapped_old_x
, f
);
223 if (wrapped_new_x
._tag
!= "None"){
224 return wrapped_new_x
;
226 return wrapped_old_x
;
232 export function tokenize(input
: string){
233 var input_matchee_pair
: Maybe
<MatcheePair
> = toSome(
237 // integer = ([+]|[-])?\d\d*
238 let integer
= (x
: MatcheePair
) =>
239 { let wrapped_x
= toSome(x
);
240 let plusMinus
= orDo(match1Char('+'), match1Char('-')); // ([+]|[-])
241 let d
= matchRange('0','9'); // \d
242 return thenDo(thenDo(thenDo(wrapped_x
,
243 zeroOrOnceDo(plusMinus
)),d
),
246 console
.log(input
+", result: ");
247 console
.log(thenDo(input_matchee_pair
, integer
));
248 // TODO: id, string, space, basic operator, 3 marks: @, {, }.