X-Git-Url: https://git.kianting.info/?a=blobdiff_plain;f=src%2Findex.ts;h=26a690eb3b71659a119668c7e4c5f202faf04a39;hb=d4dfd2e99f564ca880d40172687986ea3ce757f0;hp=60e74871dc96261bf3ddcb2eb4d3b332952f8f57;hpb=fed01e9044149985b3df74a9225ce68805b8f478;p=clo diff --git a/src/index.ts b/src/index.ts index 60e7487..26a690e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,9 @@ var fs = require('fs'); import jsTokens from "js-tokens"; import * as util from 'util'; - +import * as p from 'typescript-parsec'; +import { Token } from 'typescript-parsec'; +import { TokenType } from "./tokenize"; /** * * # REPRESENTATION @@ -21,7 +23,7 @@ export function tkTreeToSExp(t: tkTree): string{ if (t=== undefined){ str = "%undefined" }else{ - str = t.value; + str = t; } } @@ -35,156 +37,229 @@ let repr = (x : any)=>{return util.inspect(x, {depth: null})}; * # TYPES */ + +type tkTree = string | tkTree[]; + +enum TokenKind { + Seperator, // --- + Semicolon, // ; + Number, + Op, + ExprMark, // @ + ExcapeAt, // \@ + Paren, + SpaceNL, // \s\t\n\r + Id, + Str, + Comment, // /* ooo */ +} + /** - * TokenPair for tokens' parser combinator - * - * matched: the matched (now and before) tokens - * - * remained: tokens to be matched - * - * ast: abstract syntax tree + * Parsing */ -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; +const lexer = p.buildLexer([ + [true, /^\d+(\.\d+)?/g, TokenKind.Number], + [true, /^\\\@/g, TokenKind.ExcapeAt], + [true, /^\/\*([^/]|\/[^*])*\*\//g, TokenKind.Comment], + [true, /^\;/g, TokenKind.Semicolon], + [true, /^[-][-][-]/g, TokenKind.Seperator], + [true, /^[\+\-\*\/\&\|\!\^\<\>\~\=\?]+/g, TokenKind.Op], + [true, /^\@/g, TokenKind.ExprMark], + [true, /^[()\[\]{}]/g, TokenKind.Paren], + [true, /^["]([\"]|[\\].)*["]/g, TokenKind.Str], + [true, /^[']([\']|[\\].)*[']/g, TokenKind.Str], + [true, /^[()\[\]{}]/g, TokenKind.Paren], + [true, /^[^\/\\\@\s\n\t\r;]+/g, TokenKind.Id], + [true, /^(\s|\n|\r|\t)+/g, TokenKind.SpaceNL], -type Token = jsTokens.Token; -type tkTree = Token | tkTree[]; +]); /** * - * # PARSER UNITS + * # TEST */ -function toSome(x:T): Maybe{ - return {_tag: "Some", value: x}; +const inputTxt= +`import a as b; /*bacourt*/ +/* ba choir +ipsum lorem*/ + +import you as john; +--- + +臺中市\\\@ + +公園 +@1+2==3; + +console.log("122");@ + +山頂 +`; + + +const PROG = p.rule(); +const SEGMENT = p.rule(); +const IMPORT = p.rule(); +const IMPORTS = p.rule(); +const SEMICOLON = p.rule(); +const EXCAPE_AT = p.rule(); +const NOT_AT_TEXT = p.rule(); +const CONTENT = p.rule(); + +let doubleMinus = { type: 'Punctuator', value: '--' }; +let doubleMinus2 = p.str('--'); +const TERM = p.rule(); + +function applySegment(input: [Token, Token[], + Token]): tkTree[]{ + let unpackedInnerExprs = input[1].map((x)=>{return x.text}); + return ["%exprs", unpackedInnerExprs]; } -/** - * like `m ==> f` in ocaml - * @param m matchee wrapped - * @param f matching function - * @returns wrapped result - */ -function thenDo(m : Maybe, f : Function){ - if (m._tag == "None"){ - return m; - }else{ - var a : Maybe = f(m.value); - if (a._tag == "Some"){ - a.value.ast = m.value.ast.concat(a.value.ast); - } +function applySemiColon(value: Token): tkTree{ + return value.text; +} + +function applyParts(first: tkTree, + second: [Token, tkTree]):tkTree { + return ["%clo", first , second[1]]; +} + + +function applyComment(value: Token): tkTree[]{ + return [value.text]; +} + + +function applyImport(input: [Token,Token[], tkTree]) : tkTree{ + let importTail = input[1].map(x=>x.text); + return ["import"].concat(importTail); +}; + + +/* +function applyImportComment(input: [Token,Token[], + tkTree, Token]) : tkTree{ + let importTail = input[1].map(x=>x.text); + let comment = [input[3].text]; + return ["import"].concat(importTail).concat(comment); +};*/ + +function applyImports(input : [tkTree, tkTree[]]): tkTree{ + let resultBody = [input[0]].concat(input[1]); + let resultWrapper = ["%import", resultBody]; + return resultWrapper; +}; - return a; + + + +function applyNotAtText(value : Token): tkTree{ + if (value.text == "\\\@"){ + return '@'; } + else{return value.text;} +}; + +function applyText (input : tkTree): tkTree[]{ + return ["%text", input]; +}; + +function applyContent(input : tkTree[]): tkTree[]{ + return ["%content", input]; +}; + +function applySpaceNL(value : Token): tkTree{ + return value.text; } + /** - * - * @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`. + * IMPORTEE: Number, Op, Paren, Id, Str, Comment, */ -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" }; - } -} +let IMPORTEE = p.alt(p.tok(TokenKind.Number), + p.tok(TokenKind.Op), + p.tok(TokenKind.Paren), + p.tok(TokenKind.Id), + p.tok(TokenKind.Str), + p.tok(TokenKind.SpaceNL), + p.tok(TokenKind.Comment)); + +let NOT_AT = p.alt(p.tok(TokenKind.Seperator), + p.tok(TokenKind.Semicolon), + p.tok(TokenKind.Number), + p.tok(TokenKind.ExcapeAt), + p.tok(TokenKind.Op), + p.tok(TokenKind.Paren), + p.tok(TokenKind.SpaceNL), + p.tok(TokenKind.Id), + p.tok(TokenKind.Str), + p.tok(TokenKind.Comment), + ); /** - * like `f1 | f2` in regex - * @param f1 the first tried function - * @param f2 the second tried function - * @returns wrapped result + * PROG : IMPORTS '---' CONTENT; */ -function orDo(f1 : Function, f2 : Function){ - return (x : TokenPair) =>{ - let res1 : Maybe = f1(x); - if (res1._tag == "Some"){ - return res1; - }else{ - let res2 : Maybe = f2(x); - return res2; - } - } -} +PROG.setPattern( + p.lrec_sc(IMPORTS, p.seq(p.str('---'), CONTENT), applyParts) + +) /** - * like regex [^c] - * @param f input token function. one token only. - * @returns combined finction + * NOT_AT_TEXT : NOT_AT */ -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; - } - } -} +NOT_AT_TEXT.setPattern( + p.apply(NOT_AT, applyNotAtText) +); -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"}; - } - }; - } -}; +IMPORTS.setPattern( + p.apply( p.seq(IMPORT, p.rep(IMPORT)), applyImports) +); + +/** + * IMPORT : + * 'import' IMPORTEE* SEMICOLON | + * COMMENT | + */ +IMPORT.setPattern( + p.alt( + p.apply(p.seq(p.str('import'), p.rep_sc(IMPORTEE), SEMICOLON), + applyImport), + p.apply(p.tok(TokenKind.Comment), applyComment), + p.apply(p.tok(TokenKind.SpaceNL), applySpaceNL) + ) +); /** - * - * # TEST + * SEMICOLON : ';'; */ -const tokens = Array.from(jsTokens( -`import foo from\t 'bar'; -import * as util from 'util'; +SEMICOLON.setPattern( + p.apply(p.tok(TokenKind.Semicolon), applySemiColon) +); -花非花,霧\\{非霧 。{{foo();}}下 -一句`)); -console.log("RESULT="+repr(tokens)); +/** + * SEGMENT : '@' NOT_AT* '@' | + * (NOT_AT_TEXT | EXCAPE_AT)* + */ +SEGMENT.setPattern( + p.alt( + p.apply(p.rep_sc(NOT_AT_TEXT), applyText), + p.apply(p.seq(p.str('@'), p.rep(NOT_AT), p.str('@')), applySegment), + ) +); + +/** + * CONTENT : SEGMENT* + */ +CONTENT.setPattern( + p.apply(p.rep(SEGMENT), applyContent) +); -var mainTokenPair : TokenPair = { - matched : [] , - remained : tokens, - ast : []}; +let tree = p.expectSingleResult(p.expectEOF(PROG.parse(lexer.parse(inputTxt)))); -let a = thenDo(thenDo(toSome(mainTokenPair), matchToken('IdentifierName')), - notDo(matchToken('Punctuator', ';'))); -console.log("RESULT="+repr(a)); -if (a._tag == "Some"){ - console.log("SEXP="+tkTreeToSExp(a.value.ast)); -} +console.log("RESULT="+tkTreeToSExp(tree));