X-Git-Url: https://git.kianting.info/?a=blobdiff_plain;f=src%2Findex.ts;h=60e74871dc96261bf3ddcb2eb4d3b332952f8f57;hb=fed01e9044149985b3df74a9225ce68805b8f478;hp=4c1ce91924e0cfe689858d9ee19fc43e8890e0e2;hpb=f801ef14fc25ae122aaef4aede639ddb9b37006a;p=clo diff --git a/src/index.ts b/src/index.ts index 4c1ce91..60e7487 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,107 +1,68 @@ var fs = require('fs'); -import { argv, resourceUsage } from 'node:process'; -import * as tk from './tokenize.js'; +import jsTokens from "js-tokens"; import * as util from 'util'; -import { drawEllipsePath, reduceRotation } from 'pdf-lib'; -import { isTypedArray } from 'node:util/types'; -import { error } from 'node:console'; /** - * debug reprensenting + * + * # REPRESENTATION */ -let repr = (x : any)=>{return util.inspect(x, {depth: null})}; - /** - * token tree type. + * convert a `tkTree` AST to S-expr string + * @param t the `tkTree` + * @returns S-expr String */ -type tkTree = tkTree[] | tk.Token +export function tkTreeToSExp(t: tkTree): string{ + var str = ""; -/** - * concated 2 `tkTree`s - * @param x the array to be concated - * @param y the item or array to ve concated - * @returns concated tkTree array, or thrown error if can't be concated. - */ -function concat(x: tkTree, y:tkTree): tkTree[] { - if (Array.isArray(x)){ - return x.concat(y); + if (Array.isArray(t)){ + let strArray = t.map((x)=>tkTreeToSExp(x)); + str = "(" + strArray.join(" ") + ")"; }else{ - throw new Error("the tkTree can't be concated, because it's not an array."); - + if (t=== undefined){ + str = "%undefined" + }else{ + str = t.value; + } } -} -function slice(x: tkTree, index?:number, end?:number): tkTree[] { - if (Array.isArray(x)){ - return x.slice(index,end); - }else{ - throw new Error("the tkTree can't be concated, because it's not an array."); - - } + return str; } +/**inspect the inner of the representation. */ +let repr = (x : any)=>{return util.inspect(x, {depth: null})}; +/** + * + * # TYPES + */ + /** - * TokenMatcheePair for tokens' parser combinator + * TokenPair for tokens' parser combinator + * * matched: the matched (now and before) tokens + * * remained: tokens to be matched + * * ast: abstract syntax tree */ -export interface TokenMatcheePair { - matched: tk.Token[] - remained: tk.Token[] +export interface TokenPair { + matched: jsTokens.Token[] + remained: jsTokens.Token[] ast : tkTree[] } +export type Some = { _tag: "Some"; value: T }; +export type None = { _tag: "None" }; +export type Maybe = Some | None; -/** - * @description - * match one token type. - * - * it returns a function which test if the type of first token of the `remained` part of - * the argument of the function is `typ` , if it's true, update the `TokenMatcheePair` wrapped - * in `Some`. Otherwise, it returns `None`. - * * @param typ : the type to be test. - * @returns the updated `TokenMatcheePair` wrapped in `Some(x)` or `None`. - */ -export function m1TType(typ: tk.TokenType): - (m: TokenMatcheePair) => tk.Maybe { - return (m: TokenMatcheePair) => { - if (m.remained.length == 0) { - return { _tag: "None" }; - } - /** - * token to be matched - * */ - const ttbm = m.remained[0]; - - if (ttbm.type == typ) { - let new_matched = m.matched.concat(ttbm); - let result : tk.Some = { - _tag: "Some", value: { - matched: new_matched, - remained: m.remained.slice(1), - ast: ([ttbm]), - } - }; - return result; - } - else { - return { _tag: "None" }; - } - } -}; +type Token = jsTokens.Token; +type tkTree = Token | tkTree[]; /** - * type int + * + * # PARSER UNITS */ -let tInt = m1TType(tk.TokenType.INT); -let tAdd = m1TType(tk.TokenType.I_ADD); -let tMul = m1TType(tk.TokenType.I_MUL); - - -argv.forEach((val, index) => { - console.log(`${index}=${val}`); -}); - +function toSome(x:T): Maybe{ + return {_tag: "Some", value: x}; +} /** * like `m ==> f` in ocaml @@ -109,18 +70,38 @@ argv.forEach((val, index) => { * @param f matching function * @returns wrapped result */ -function thenDo(m : tk.Maybe, f : Function){ +function thenDo(m : Maybe, f : Function){ if (m._tag == "None"){ return m; }else{ - var a : tk.Maybe = f(m.value); + var a : Maybe = f(m.value); if (a._tag == "Some"){ - a.value.ast = concat(m.value.ast, a.value.ast); + a.value.ast = m.value.ast.concat(a.value.ast); } return a; } } +/** + * + * @param m : the `TokenPair` to be consumed. + * @returns if the length of `m.remained` >= 1; consumes the matchee by 1 token + * and wraps it in `Some`, + * otherwise, returns `None`. + */ +export function matchAny(m: TokenPair): Maybe { + if (m.remained.length >= 1) { + return { + _tag: "Some", value: { + matched: m.matched.concat(m.remained[0]), + remained: m.remained.slice(1), + ast : [m.remained[0]], + } + }; + } else { + return { _tag: "None" }; + } +} /** * like `f1 | f2` in regex @@ -129,96 +110,81 @@ function thenDo(m : tk.Maybe, f : Function){ * @returns wrapped result */ function orDo(f1 : Function, f2 : Function){ - return (x : TokenMatcheePair) =>{ - let res1 : tk.Maybe = f1(x); + return (x : TokenPair) =>{ + let res1 : Maybe = f1(x); if (res1._tag == "Some"){ return res1; }else{ - let res2 : tk.Maybe = f2(x); + let res2 : Maybe = f2(x); return res2; } - } - -} - -let midfix = (f : Function, signal? : string) => (x : TokenMatcheePair)=>{ - var a = f(x); - if (a._tag == "Some"){ - let ast_head : tkTree[] = slice(a.value.ast,0,a.value.ast.length-3); - let ast_tail : tkTree[] = slice(a.value.ast,a.value.ast.length-3); - let new_ast = [ast_tail]; - a.value.ast = new_ast; - - console.log("+"+signal+"+"+repr(a)); - - - } - return a; + } } /** - * - * fac1 = int MUL int + * like regex [^c] + * @param f input token function. one token only. + * @returns combined finction */ -//let fac1 = midfix((x : TokenMatcheePair)=> -// thenDo(thenDo(thenDo(tk.toSome(x), tInt), tMul), tInt)); - -let fac1 = (x : TokenMatcheePair) => { - let a = midfix((x : TokenMatcheePair)=> - thenDo(thenDo(thenDo(tk.toSome(x), tInt), tMul), tInt), "fac1")(x); - - return a; +function notDo(f : Function){ + return (x : TokenPair) =>{ + let res1 : Maybe = f(x); + if (res1._tag == "Some"){ + return {_tag:"None"}; + }else{ + let res2 = matchAny(x); + return res2; + } + } } - -/** - * - * fac2 = int MUL int - */ -let fac2 = tInt; +function matchToken(typeName : string, value? : string): + (t : TokenPair) => Maybe{ + return (t)=>{ + let headToken = t.remained[0]; + if (headToken.type != typeName){ + return {_tag:"None"}; + }else{ + if (value === undefined || value == headToken.value){ + let newTokenPair = { + matched: t.matched.concat(headToken), + remained: t.remained.slice(1), + ast : [headToken] + }; + return {_tag : "Some", value : newTokenPair}; + }else{ + return {_tag:"None"}; + } + }; + } +}; -/** - * fac = fac1 | fac2 - */ -let fac = orDo(fac1, fac2); - /** * - * expr1 = fac ADD fac + * # TEST */ -let expr1 = midfix((x : TokenMatcheePair)=> - thenDo(thenDo(thenDo(tk.toSome(x), fac), tAdd), fac), "expr1"); -/** - * expr2 = fac - */ -let expr2 = fac; +const tokens = Array.from(jsTokens( +`import foo from\t 'bar'; +import * as util from 'util'; -/** - * expr = expr1 | expr2 - */ -let expr = orDo(expr1, expr2); +花非花,霧\\{非霧 。{{foo();}}下 +一句`)); +console.log("RESULT="+repr(tokens)); -let tokens = tk.tokenize("2+3*4");//tk.tokenize(argv[2]); -let tokensFiltered = tokens.filter( - (x)=>{return (x.type != tk.TokenType.NL - && x.type != tk.TokenType.SP)}); +var mainTokenPair : TokenPair = { + matched : [] , + remained : tokens, + ast : []}; -let wrappedTokens : tk.Maybe = - tk.toSome({ - matched : [] , - remained : tokensFiltered, - ast : []}); +let a = thenDo(thenDo(toSome(mainTokenPair), matchToken('IdentifierName')), + notDo(matchToken('Punctuator', ';'))); -let beta = expr({ - matched : [] , - remained : tokensFiltered, - ast : []}); - -console.log(repr(wrappedTokens)); - -console.log(repr(beta)); +console.log("RESULT="+repr(a)); +if (a._tag == "Some"){ + console.log("SEXP="+tkTreeToSExp(a.value.ast)); +}