syntax.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. 'use strict';
  2. const Char = {
  3. Digit: Regex(/^[0-9]$/),
  4. NonZero: Regex(/^[1-9]$/),
  5. NotDigit: Regex(/^[^0-9]$/),
  6. Alphabet: Regex(/^[A-Za-z]$/),
  7. DoubleQuote: $1('"'),
  8. SingleQuote: $1("'"),
  9. Dot: $1('.'),
  10. Semicolon: $1(';'),
  11. Space: one_of(' ', ' '),
  12. NotSpace: $_(one_of(' ', ' ')),
  13. Any: $u(Str, $(s => s.length >= 1)),
  14. ForbiddenInId: one_of.apply({}, map(
  15. CR + LF + '`' + `\\'"()[]{}:,.;!~&|+-*%^<>=`,
  16. // divide "/" is available
  17. x => x))
  18. }
  19. Pattern.PrefixOperator = function (name, operator) {
  20. check(Pattern.PrefixOperator, arguments, {
  21. name: Str, operator: Optional(Str)
  22. })
  23. operator = operator || name
  24. return Pattern('Operator', name, map(operator, (char, index) => Unit(
  25. $1(char), '', (index < operator.length-1)? Any: Char.NotSpace
  26. )))
  27. }
  28. Pattern.TextOperator = function (name, operator) {
  29. check(Pattern.PrefixOperator, arguments, {
  30. name: Str, operator: Optional(Str)
  31. })
  32. operator = operator || name
  33. return Pattern('Operator', name, map(operator, (char, index) => Unit(
  34. $1(char), '', (index < operator.length-1)? Any: Char.Space
  35. )))
  36. }
  37. Pattern.Operator = function (name, operator) {
  38. check(Pattern.Operator, arguments, {
  39. name: Str, operator: Optional(Str)
  40. })
  41. operator = operator || name
  42. return Pattern('Operator', name, map(operator, (char, index) => Unit(
  43. $1(char)
  44. )))
  45. }
  46. const Tokens = [
  47. Pattern('String', 'RawString', [
  48. Unit(Char.SingleQuote),
  49. Unit($_(Char.SingleQuote), '*'),
  50. Unit(Char.SingleQuote)
  51. ]),
  52. Pattern('String', 'FormatString', [
  53. Unit(Char.DoubleQuote),
  54. Unit($_(Char.DoubleQuote), '*'),
  55. Unit(Char.DoubleQuote)
  56. ]),
  57. Pattern('RawCode', 'RawCode', [
  58. Unit($1('/')),
  59. Unit($1('~')),
  60. CustomUnit((char, next) => `${char}${next}` != '~/', '*'),
  61. Unit($1('~')),
  62. Unit($1('/'))
  63. ]),
  64. Pattern('Comment', 'Comment', [
  65. Unit($1('/')),
  66. Unit($1('*')),
  67. CustomUnit((char, next) => `${char}${next}` != '*/', '*'),
  68. Unit($1('*')),
  69. Unit($1('/'))
  70. ]),
  71. Pattern('Blank', 'Space', [
  72. Unit($u(Char.Space, one_of(CR, TAB)), '+')
  73. ]),
  74. Pattern('Blank', 'Linefeed', [
  75. Unit($1(LF), '+')
  76. ]),
  77. Pattern('Blank', 'Linefeed', [
  78. Unit(Char.Semicolon, '+')
  79. ]),
  80. Pattern.Operator('('),
  81. Pattern.Operator(')'),
  82. Pattern.Operator('['),
  83. Pattern.Operator(']'),
  84. Pattern.Operator('{'),
  85. Pattern.Operator('}'),
  86. Pattern.Operator(','),
  87. Pattern.Operator(':'),
  88. Pattern.Operator('.{'),
  89. Pattern.Operator('..{'),
  90. Pattern.Operator('...{'),
  91. Pattern.Operator('.['),
  92. Pattern.Operator('..['),
  93. Pattern.Operator('..'), // ..Identifier = Inline Comment
  94. Pattern.Operator('.'),
  95. // name of simple operator starts with a capital alphabet
  96. Pattern.Operator('!='),
  97. Pattern.PrefixOperator('!'),
  98. Pattern.Operator('||'),
  99. Pattern.Operator('&&'),
  100. Pattern.PrefixOperator('~'),
  101. Pattern.Operator('|'),
  102. Pattern.Operator('&'),
  103. Pattern.Operator('->'),
  104. Pattern.Operator('<-'),
  105. Pattern.PrefixOperator('Negate', '-'),
  106. Pattern.Operator('-'),
  107. //Pattern.PrefixOperator('Positive', '+'),
  108. Pattern.Operator('+'),
  109. Pattern.Operator('**'),
  110. Pattern.Operator('*'),
  111. Pattern.Operator('/'),
  112. //Pattern.PrefixOperator('Parameter', '%'), // ugly, use dot
  113. Pattern.Operator('%'),
  114. Pattern.Operator('^'),
  115. Pattern.Operator('=='),
  116. Pattern.Operator('=>'),
  117. Pattern.Operator('='),
  118. Pattern.Operator('<<'),
  119. Pattern.Operator('>>'),
  120. Pattern.Operator('<'),
  121. Pattern.Operator('>'),
  122. Pattern.Operator('<='),
  123. Pattern.Operator('>='),
  124. Pattern.TextOperator('Is', 'is'),
  125. Pattern.TextOperator('~', 'not'),
  126. Pattern('Number', 'Exponent', [
  127. Unit(Char.Digit, '+'),
  128. Unit(Char.Dot),
  129. Unit(Char.Digit, '+'),
  130. Unit(one_of('E', 'e')),
  131. Unit(one_of('+', '-'), '?'),
  132. Unit(Char.Digit, '+')
  133. ]),
  134. Pattern('Number', 'Float', [
  135. Unit(Char.Digit, '+'),
  136. Unit(Char.Dot),
  137. Unit(Char.Digit, '+')
  138. ]),
  139. Pattern('Number', 'Integer', [
  140. Unit(Char.Digit, '+')
  141. ]),
  142. Pattern('Name', 'Name', [
  143. Unit($n(Char.NotDigit, Char.NotSpace, $_(Char.ForbiddenInId))),
  144. Unit($n(Char.NotSpace, $_(Char.ForbiddenInId)), '*')
  145. ])
  146. ]
  147. const SimpleOperand = $n(
  148. Token.Valid,
  149. $(token => is(token.matched.name, one_of(
  150. 'Exponent', 'Float', 'Integer',
  151. 'RawString', 'FormatString',
  152. 'Identifier', 'Member'
  153. ))
  154. ))
  155. const SimpleOperator = {
  156. Sentinel: { type: 'N/A', priority: -1, assoc: 'left' },
  157. Parameter: { type: 'prefix', priority: 100, assoc: 'right' },
  158. Access: { type: 'infix', priority: 99, assoc: 'left' },
  159. Call: { type: 'infix', priority: 98, assoc: 'left' },
  160. Get: { type: 'infix', priority: 98, assoc: 'left' },
  161. Is: { type: 'infix', priority: 10, assoc: 'left' },
  162. Negate: { type: 'prefix', priority: 85, assoc: 'right' },
  163. '+': { type: 'infix', priority: 50, assoc: 'left' },
  164. '-': { type: 'infix', priority: 50, assoc: 'left' },
  165. '*': { type: 'infix', priority: 80, assoc: 'left' },
  166. '/': { type: 'infix', priority: 70, assoc: 'left' },
  167. '%': { type: 'infix', priority: 75, assoc: 'left' },
  168. '^': { type: 'infix', priority: 90, assoc: 'right' },
  169. '==': { type: 'infix', priority: 30, assoc: 'left' },
  170. '!=': { type: 'infix', priority: 20, assoc: 'left' },
  171. '>': { type: 'infix', priority: 20, assoc: 'left' },
  172. '>=': { type: 'infix', priority: 20, assoc: 'left' },
  173. '<': { type: 'infix', priority: 20, assoc: 'left' },
  174. '<=': { type: 'infix', priority: 20, assoc: 'left' },
  175. '!': { type: 'prefix', priority: 85, assoc: 'right' },
  176. '&&': { type: 'infix', priority: 40, assoc: 'left' },
  177. '||': { type: 'infix', priority: 30, assoc: 'left' },
  178. '~': { type: 'prefix', priority: 85, assoc: 'right' },
  179. '&': { type: 'infix', priority: 40, assoc: 'left' },
  180. '|': { type: 'infix', priority: 30, assoc: 'left' }
  181. }
  182. SetEquivalent(SimpleOperator, $(
  183. token => has(SimpleOperator, token.matched.name)
  184. ))
  185. const KeywordList = ['module', 'export', 'use', 'as', 'import', 'let', 'outer', 'return', 'that', 'for', 'in', 'struct', 'to', 'by', 'f', 'g', 'h', 'global', 'upper', 'local']
  186. const TokenList = list(new Set(map(Tokens, t => t.name)))
  187. const Syntax = mapval({
  188. Id: ['Identifier', 'RawString'],
  189. Constraint: 'Identifier',
  190. Module: 'ModuleName ExportList Program',
  191. ModuleName: '~module Id',
  192. ExportList: ['Export NextExport', ''],
  193. Export: '~export AsList',
  194. NextExport: ['Export NextExport', ''],
  195. Program: 'Command NextCommand',
  196. Command: [
  197. 'Use',
  198. 'Import',
  199. 'FunDef',
  200. 'Let',
  201. 'Return',
  202. 'Assign',
  203. 'Outer',
  204. 'Expr'
  205. ],
  206. NextCommand: ['Command NextCommand', ''],
  207. Use: '~use AsList',
  208. As: ['Id ~as Id', 'Id'],
  209. AsList: ['As NextAs', '( As NextAs )'],
  210. NextAs: [', As NextAs', ''],
  211. Import: '~import IdList',
  212. IdList: ['Id NextId', '( Id NextId )'],
  213. NextId: [', Id NextId', ''],
  214. Let: '~let Id = Expr',
  215. Assign: 'LeftVal = Expr',
  216. Outer: '~outer Id = Expr',
  217. LeftVal: 'Id MemberNext KeyNext',
  218. MemberNext: ['Access Member MemberNext', ''],
  219. KeyNext: ['Get Key KeyNext', ''],
  220. Return: '~return Expr',
  221. Expr: [
  222. 'MapExpr'
  223. ],
  224. Concept: '{ Id That FilterList }',
  225. That: ['|', '~that'],
  226. FilterList: 'Filter NextFilter',
  227. NextFilter: [', Filter NextFilter', ''],
  228. Filter: 'Simple',
  229. For: [':', '~for'],
  230. IteratorExpr: [
  231. '.[ MapOperand For ListExprArgList ListExprFilterList ]'
  232. ],
  233. ListExpr: [
  234. '[ MapOperand For ListExprArgList ListExprFilterList ]'
  235. ],
  236. ListExprFilterList: [', FilterList', ''],
  237. ListExprArgList: ['ListExprArg NextListExprArg'],
  238. ListExprArg: ['Id ~in Simple'],
  239. NextListExprArg: [', ListExprArg NextListExprArg', ''],
  240. PairListExpr: ['[ AdvPair NextAdvPair ]'],
  241. NextAdvPair: [', AdvPair NextAdvPair', ''],
  242. AdvPair: 'MapOperand : Expr',
  243. Struct: '~struct Hash',
  244. FiniteSet: '{ ItemList }',
  245. MapExpr: 'MapOperand MapNext',
  246. MapNext: [
  247. 'MapOperator MapOperand MapNext',
  248. ''
  249. ],
  250. MapOperator: [
  251. '->', '<-',
  252. '>>', '<<',
  253. '~to', '~by',
  254. '**', '=>'
  255. ],
  256. MapOperand: [
  257. 'RawCode',
  258. 'FiniteSet',
  259. 'Hash', 'HashLambda',
  260. 'List', 'ListLambda',
  261. 'PairListExpr',
  262. 'SimpleLambda',
  263. 'BodyLambda',
  264. 'IteratorExpr',
  265. 'ListExpr',
  266. 'FunExpr',
  267. 'Concept',
  268. 'Struct',
  269. 'Simple'
  270. ],
  271. ItemList: 'Item NextItem',
  272. Item: 'Expr',
  273. NextItem: [', Item NextItem', ''],
  274. PairList: 'Pair NextPair',
  275. Pair: 'Id : Expr',
  276. NextPair: [', Pair NextPair', ''],
  277. Hash: ['{ }', '{ PairList }'],
  278. List: [
  279. '[ ]', 'Get [ ]', // Get operator may be inserted by get_tokens()
  280. '[ ItemList ]', 'Get [ ItemList ]'
  281. ],
  282. HashLambda: ['..{ }', '..{ PairList }'],
  283. ListLambda: ['..[ ]', '..[ ItemList ]'],
  284. SimpleLambda: [
  285. '.{ LambdaParaList SimpleLambda }',
  286. '.{ LambdaParaList Simple }'
  287. ],
  288. BodyLambda: '...{ Program }',
  289. LambdaParaList: [
  290. '( LambdaPara NextLambdaPara ) ->',
  291. 'LambdaPara ->',
  292. ''
  293. ],
  294. LambdaPara: ['Identifier'],
  295. NextLambdaPara: [', LambdaPara NextLambdaPara', ''],
  296. ParaList: ['( )', '( Para NextPara )'],
  297. Para: 'Constraint PassFlag Id',
  298. NextPara: [', Para NextPara', ''],
  299. PassFlag: ['&', '*', ''],
  300. Target: ['-> Constraint', '->', ''],
  301. Body: '{ Program }',
  302. FunFlag: ['~g :', '~h :', '~f :', '~global :', '~upper :', '~local :'],
  303. NoFlag: ['Call', ''],
  304. FunExpr: [
  305. 'FunFlag ParaList Target Body',
  306. 'NoFlag ParaList Target Body'
  307. ],
  308. Effect: ['~global', '~upper', '~local'],
  309. FunDef: 'Effect Id Call ParaList Target Body',
  310. // ↑ call operator will be inserted automatically
  311. //Simple: () => parse_simple,
  312. Simple: 'Identifier',
  313. Wrapped: '( Simple )',
  314. Key: '[ Simple ]',
  315. ArgList: [
  316. '( )',
  317. '( KeyArg NextKeyArg )',
  318. '( Arg NextArg )'
  319. ],
  320. Arg: 'Simple',
  321. NextArg: [', Arg NextArg', ''],
  322. KeyArg: 'Id : Simple',
  323. NextKeyArg: [', KeyArg NextKeyArg', '']
  324. }, function (rule) {
  325. let split = (string => string? string.split(' '): [])
  326. let derivations = (array => ({ derivations: array }))
  327. return transform(rule, [
  328. { when_it_is: Str, use: d => derivations([split(d)]) },
  329. { when_it_is: List, use: r => derivations(map(r, d => split(d))) },
  330. { when_it_is: Otherwise, use: r => r }
  331. ])
  332. })
  333. const PartList = list(cat(
  334. Object.keys(Syntax), map(KeywordList, x => '~'+x), TokenList,
  335. ['Call','Get','Identifier']
  336. ))
  337. assert(fold(PartList, {}, function (name,state) {
  338. if (state === false) {
  339. return false
  340. } else if(state[name]) {
  341. console.log(name)
  342. return false
  343. } else {
  344. state[name] = true
  345. return state
  346. }
  347. }))