]>
git.kianting.info Git - clo/blob - src/parser.ts
2 * parser.ts - parser and js generator of clo.
4 import * as p from
'typescript-parsec';
5 import { Token
} from
'typescript-parsec';
13 * convert a `tkTree` AST to S-expr string
14 * @param t the `tkTree`
15 * @returns S-expr String
17 export function tkTreeToSExp(t: tkTree): string{
20 if (Array.isArray(t)){
21 let strArray = t.map((x)=>tkTreeToSExp(x));
22 str = "(" + strArray.join("◎") + ")";
34 export type tkTree
= string | tkTree
[];
53 const lexer
= p
.buildLexer([
54 [true, /^\d
+(\
.\d
+)?/g
, TokenKind
.Number],
55 [true, /^[\\][\\]/g
, TokenKind
.Op
],
56 [true, /^\\\@
/g
, TokenKind
.ExcapeAt
],
57 [true, /^\
/\
*([^/]|\
/[^*])*\
*\
//g, TokenKind.Comment],
58 [true, /^\
;/g
, TokenKind
.Semicolon
],
59 [true, /^[-][-][-]/g
, TokenKind
.Seperator
],
60 [true, /^[\
+\
-\
*\
/\
&\
|\
!\
^\
<\
>\
~\
=\?]+/g
, TokenKind
.Op
],
61 [true, /^\@
/g
, TokenKind
.ExprMark
],
62 [true, /^[()\
[\
]{}]/g
, TokenKind
.Paren
],
63 [true, /^[\"]([^\"]|[\\].)*[\"]/g
, TokenKind
.Str
],
64 [true, /^[\']([^\']|[\\].)*[\']/g
, TokenKind
.Str
],
65 [true, /^[()\
[\
]{}]/g
, TokenKind
.Paren
],
66 [true, /^[^\
/\\\@\s
\n\t\r;]+/g
, TokenKind
.Id
],
67 [true, /^(\s
|\n|\r|\t)+/g
, TokenKind
.SpaceNL
],
78 const PROG
= p
.rule
<TokenKind
, tkTree
>();
79 const SEGMENT
= p
.rule
<TokenKind
, tkTree
>();
80 const IMPORT
= p
.rule
<TokenKind
, tkTree
>();
81 const IMPORTS
= p
.rule
<TokenKind
, tkTree
>();
82 const SEMICOLON
= p
.rule
<TokenKind
, tkTree
>();
83 const NOT_AT_TEXT
= p
.rule
<TokenKind
, tkTree
>();
84 const CONTENT
= p
.rule
<TokenKind
, tkTree
>();
87 function applySegment(input
: [Token
<TokenKind
>, Token
<TokenKind
>[],
88 Token
<TokenKind
>]): tkTree
[]{
89 let unpackedInnerExprs
= input
[1].map((x
)=>{return x
.text
});
90 return ["%exprs", unpackedInnerExprs
];
93 function applySemiColon(value
: Token
<TokenKind
.Semicolon
>): tkTree
{
97 function applyParts(first
: tkTree
,
98 second
: [Token
<TokenKind
>, tkTree
]):tkTree
{
99 return ["%clo", first
, second
[1]];
102 function applyPartsWithoutImport(parsed
: [Token
<TokenKind
>, tkTree
]):tkTree
{
103 return ["%clo", "" , parsed
[1]];
107 function applyComment(value
: Token
<TokenKind
.Comment
>): tkTree
[]{
112 function applyImport(input
: [Token
<TokenKind
>,Token
<TokenKind
>[], tkTree
]) : tkTree
{
113 let importTail
= input
[1].map(x
=>x
.text
);
114 return ["import"].concat(importTail
);
119 function applyImportComment(input: [Token<TokenKind>,Token<TokenKind>[],
120 tkTree, Token<TokenKind.Comment>]) : tkTree{
121 let importTail = input[1].map(x=>x.text);
122 let comment = [input[3].text];
123 return ["import"].concat(importTail).concat(comment);
126 function applyImports(input
: [tkTree
, tkTree
[]]): tkTree
{
127 let resultBody
= [input
[0]].concat(input
[1]);
128 let resultWrapper
= ["%import", resultBody
];
129 return resultWrapper
;
135 function applyNotAtText(value
: Token
<TokenKind
>): tkTree
{
136 if (value
.text
== "\\\@"){
139 else{return value
.text
;}
142 function applyText (input
: tkTree
): tkTree
[]{
143 return ["%text", input
];
146 function applyContent(input
: tkTree
[]): tkTree
[]{
147 return ["%content", input
];
150 function applySpaceNL(value
: Token
<TokenKind
.SpaceNL
>): tkTree
{
155 * IMPORTEE: Number, Op, Paren, Id, Str, Comment,
157 let IMPORTEE
= p
.alt(p
.tok(TokenKind
.Number),
159 p
.tok(TokenKind
.Paren
),
161 p
.tok(TokenKind
.Str
),
162 p
.tok(TokenKind
.SpaceNL
),
163 p
.tok(TokenKind
.Comment
));
165 let NOT_AT
= p
.alt(p
.tok(TokenKind
.Seperator
),
166 p
.tok(TokenKind
.Semicolon
),
167 p
.tok(TokenKind
.Number),
168 p
.tok(TokenKind
.ExcapeAt
),
170 p
.tok(TokenKind
.Paren
),
171 p
.tok(TokenKind
.SpaceNL
),
173 p
.tok(TokenKind
.Str
),
174 p
.tok(TokenKind
.Comment
),
178 * PROG : IMPORTS '---' CONTENT | '---' CONTNENT
182 p
.lrec_sc(IMPORTS
, p
.seq(p
.str('---'), CONTENT
), applyParts
),
183 p
.apply(p
.seq(p
.str('---'), CONTENT
), applyPartsWithoutImport
))
188 * NOT_AT_TEXT : NOT_AT
190 NOT_AT_TEXT
.setPattern(
191 p
.apply(NOT_AT
, applyNotAtText
)
195 p
.apply( p
.seq(IMPORT
, p
.rep(IMPORT
)), applyImports
)
200 * 'import' IMPORTEE* SEMICOLON |
205 p
.apply(p
.seq(p
.str('import'), p
.rep_sc(IMPORTEE
), SEMICOLON
),
207 p
.apply(p
.tok(TokenKind
.Comment
), applyComment
),
208 p
.apply(p
.tok(TokenKind
.SpaceNL
), applySpaceNL
)
216 SEMICOLON
.setPattern(
217 p
.apply(p
.tok(TokenKind
.Semicolon
), applySemiColon
)
223 * SEGMENT : '@' NOT_AT* '@' |
224 * (NOT_AT_TEXT | EXCAPE_AT)*
228 p
.apply(p
.rep_sc(NOT_AT_TEXT
), applyText
),
229 p
.apply(p
.seq(p
.str('@'), p
.rep(NOT_AT
), p
.str('@')), applySegment
),
237 p
.apply(p
.rep(SEGMENT
), applyContent
)
243 * the head part of the output JS code : before import
246 /* clo, a typesetting engine, generated JS file*/
247 /* CLO: beginning of head*/
249 let cloLib = require("./src/libclo/index.js");
250 let clo = new cloLib.Clo();
252 /* CLO: end of head*/\n`
255 * the middle part of the output JS code : between import part and content part
258 /* CLO: beginning of middle part*/
259 clo.mainStream = /* CLO: end of middle part*/
262 /* CLO: beginning of end part*/
264 /*CLO : end of end part*/
268 * Convert `tree` (ASTTree; `tkTree`) to JS Code.
270 export function treeToJS(tree
: tkTree
): string{
274 let totalResult
= outputHead
+ treeToJS(tree
[1]) +
275 outputMiddle
+ treeToJS(tree
[2]) + outputEnd
;
278 if (head
== "%import"){
279 let imports
= tree
[1];
280 if (Array.isArray(imports
)){
281 let importsText
= imports
.map(
283 if (Array.isArray(x
)){
284 return x
.join('') + ';';
290 let importTextCombined
= importsText
.join('');
291 return importTextCombined
;
297 if (head
== "%content"){
299 if (Array.isArray(tail
)){
300 if (tail
.length
== 1){
301 return tail
.map((x
)=>treeToJS(x
)).join("').concat('")+ ";";
303 let tailStrings
= tail
.map((x
)=>treeToJS(x
));
304 return "(" + tailStrings
.join(').concat(') + ");";
309 if (head
== "%text"){
310 let textContents
= tree
[1];
311 if (Array.isArray(textContents
)){
312 let decoratedArray
= textContents
313 .flatMap(x
=>String(x
))
314 .map(x
=>x
.replace("\`","\\\`"));
316 return "[`" + decoratedArray
.join("\`, \`") + "`]";
318 let decorated
= textContents
.replace("\`","\\\`");
320 return "[`" + decorated
+ "`]";
324 if (head
== "%exprs"){
325 let content
= tree
[1];
326 if (Array.isArray(content
)){
327 let flattenContent
= content
.flat();
328 return flattenContent
.join('');
336 if (Array.isArray(tree
)){
337 return tree
.join('');
346 * `inputText` to `tkTree` (ASTTree)
348 export function inputTextToTree(inputText
: string){
349 return p
.expectSingleResult(
350 p
.expectEOF(PROG
.parse(lexer
.parse(inputText
))));