├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── README.md
├── example
├── package.json
├── result.html
├── runner.js
├── runtimes
│ ├── .gitignore
│ ├── build.sh
│ ├── index.coffee
│ ├── index.html
│ ├── package.json
│ └── template.reiny
├── template.js
└── template.reiny
├── grammars
├── _entry.pegcoffee
├── expression.pegcoffee
├── primitive.pegcoffee
└── statement.pegcoffee
├── package.json
├── reiny
├── script
├── build
└── build-parser
├── src
├── cli.coffee
├── compiler.coffee
├── format-error.coffee
├── index.coffee
├── preprocess.coffee
├── runtime.coffee
└── style-compiler.coffee
└── test
├── broken
├── identifier.reiny
└── top-level-statement.reiny
├── fixtures
├── binary.reiny
├── child-type.reiny
├── classname.reiny
├── code.reiny
├── comment.reiny
├── custom-element.reiny
├── direct-element.reiny
├── embeded-code.reiny
├── entity-ref.reiny
├── example.reiny
├── for.reiny
├── header.reiny
├── identifier.reiny
├── if.reiny
├── indent.reiny
├── inline-expr.reiny
├── mergeable-object.reiny
├── modifiers.reiny
├── nested-style.reiny
├── no-indent-element.reiny
├── prop-types.reiny
├── style.reiny
└── text.reiny
├── preprocess-test.coffee
├── style-compiler-test.coffee
└── test.coffee
/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/d866fb556184cc1edffd9d0f1ca205fe1916a7f6/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 |
7 | # Runtime data
8 | pids
9 | *.pid
10 | *.seed
11 |
12 | # Directory for instrumented libs generated by jscoverage/JSCover
13 | lib-cov
14 |
15 | # Coverage directory used by tools like istanbul
16 | coverage
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
29 | node_modules
30 | lib
31 | runtime.js
32 | parser.js
33 | grammar.pegcoffee
34 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | test
3 | script
4 | example
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v0.4.1
2 |
3 | - Readable error
4 |
5 | ## v0.4.0
6 |
7 | - mithril / mercury support
8 |
9 | ## v0.3.6
10 |
11 | - Enhance comment stripping
12 |
13 | ## v0.3.6
14 |
15 | - Start changelog
16 | - if else, else support
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Reiny
2 |
3 | Template engine for React / Mithril / Mercury
4 |
5 | ```
6 | npm install reiny --save
7 | ```
8 |
9 | - gulp: [mizchi/gulp-reiny](https://github.com/mizchi/gulp-reiny "mizchi/gulp-reiny")
10 | - browserify: [mizchi/reinify](https://github.com/mizchi/reinify "mizchi/reinify")
11 | - atom mode: [mizchi/language-reiny](https://github.com/mizchi/language-reiny "mizchi/language-reiny")
12 |
13 | ```
14 | apm install language-reiny
15 | ```
16 |
17 | ## Goals
18 |
19 | - Jade like template engine
20 | - Generate react/mithril/mercury element
21 | - Inline css friendly
22 | - Inline babel preprocessor
23 | - Inline propTypes
24 |
25 | ## Example
26 |
27 | template.reiny
28 |
29 | ```
30 | // declare propTypes
31 | @greeting: string
32 | @items: number[]
33 |
34 | // props and inline style
35 | .main.container(
36 | data-id = 'this-is-id'
37 | ) {
38 | background-color: #eee
39 | width: 640px
40 | height: { 40 * 12 }
41 | font-size: 1em
42 | }
43 | // text
44 | h1 This is a title
45 |
46 | // ref alias by & modifier
47 | foo&foo
48 |
49 | | expand with span
50 | span = @greeting
51 |
52 | // if syntax
53 | if false
54 | a hoge fuga aaa
55 |
56 | // inline expression
57 | if { 2 > 1 }
58 | a(key='fooo') hoge fuga aaa
59 |
60 | // for syntax
61 | ul
62 | for i in @items
63 | li(key=i) = i
64 |
65 | // object mixin as property
66 | - let o = {'data-a': 'aaa', 'data-b': 'bbb'};
67 | .foo(
68 | > o
69 | onClick = {- function(){console.log('foo')} -}
70 | )
71 |
72 | // mutli line code
73 | ---
74 | let Foo = React.createClass({
75 | render: () => {
76 | return React.createElement('div', {className: 'foo'});
77 | }
78 | })
79 | ---
80 | // CamelCase becomes element reference
81 | Foo()
82 |
83 | // Embed element direactly
84 | - var el = React.createElement(Foo, {})
85 | +(el)
86 |
87 | ```
88 |
89 | ```
90 | npm install -g reiny
91 | reiny template.reiny -o template.js
92 | ```
93 |
94 | or node module
95 |
96 | ```js
97 | var reiny = require('reiny/lib');
98 | reiny.compile('foo.bar(prop=1) text'); // generate code string
99 | ```
100 |
101 | ## How to Use
102 |
103 | Use template with runner
104 |
105 | ```
106 | npm install reiny --save-dev
107 | ```
108 |
109 | ```js
110 | global.React = require('react');
111 | var template = require('./template');
112 | var C = React.createClass({
113 | propTypes: template.propTypes || {},
114 | render: function(){
115 | return template(this.props);
116 | }
117 | });
118 |
119 | console.log(React.renderToStaticMarkup(
120 | React.createElement(C, {greeting: 'hello', items: [1, 2]})
121 | ));
122 | ```
123 |
124 | ```html
125 |
126 |
This is a title
127 |
expand with span
128 |
hello
129 |
hoge fuga aaa
130 |
134 |
135 |
136 |
137 |
138 |
139 | ```
140 |
141 | ## SCSS Compiler(experimental)
142 |
143 | ```
144 | .foo {
145 | color: 'green'
146 | }
147 | if true
148 | if true
149 | .quux {
150 | color: #eee
151 | }
152 | .bar {
153 | color: 'red'
154 | }
155 | .baz {
156 | color: 'blue'
157 | }
158 | if false
159 | .fuba {
160 | color: value
161 | }
162 | ```
163 |
164 | to
165 |
166 | ```
167 | reiny template.reiny --scss
168 | ```
169 |
170 | ```
171 | .foo {
172 | color:'green';
173 | .bar {
174 | color:'red';
175 | .baz {
176 | color:'blue';
177 | }
178 | .fuba {
179 | color:$value;
180 | }
181 | }
182 | .quux {
183 | color:'#eee';
184 | }
185 | }
186 | ```
187 |
188 | ## How to develop
189 |
190 | ```
191 | ./script/build
192 | ```
193 |
194 | ## LICENSE
195 |
196 | MIT
197 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "example.js",
6 | "scripts": {
7 | "build": "$(npm bin)/reiny template.reiny -o template.js",
8 | "exec": "node runner.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "author": "mizchi",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "reiny": "file:.."
15 | },
16 | "dependencies": {
17 | "camelize": "^1.0.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/example/result.html:
--------------------------------------------------------------------------------
1 | This is a title
expand with spanhellohoge fuga aaa
2 |
--------------------------------------------------------------------------------
/example/runner.js:
--------------------------------------------------------------------------------
1 | global.React = require('react');
2 | var template = require('./template');
3 | var C = React.createClass({
4 | propTypes: template.propTypes,
5 | render: function(){
6 | return template(this.props);
7 | }
8 | });
9 |
10 | console.log(React.renderToStaticMarkup(
11 | React.createElement(C, {greeting: 'hello', items: [1, 2]})
12 | ))
13 |
--------------------------------------------------------------------------------
/example/runtimes/.gitignore:
--------------------------------------------------------------------------------
1 | *.js
2 |
--------------------------------------------------------------------------------
/example/runtimes/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # $(npm bin)/reiny template.reiny -o template.js
4 | $(npm bin)/reiny template.reiny -o mithril.js --target mithril
5 | $(npm bin)/reiny template.reiny -o mercury.js --target mercury
6 | $(npm bin)/reiny template.reiny -o react.js --target react
7 | browserify -t coffeeify --extension='.coffee' index.coffee -o bundle.js
8 |
--------------------------------------------------------------------------------
/example/runtimes/index.coffee:
--------------------------------------------------------------------------------
1 | global.m = require 'mithril'
2 | global.deku = require 'deku'
3 | global.React = require 'react'
4 | global.hg = require 'mercury'
5 | global.h = hg.h
6 |
7 | props = {greeting: 'hello', items: [1, 2]}
8 |
9 | window.addEventListener 'DOMContentLoaded', ->
10 | C = React.createClass
11 | render: -> require('./react')(@props)
12 |
13 | React.render(
14 | React.createElement(C, props)
15 | document.querySelector('#react')
16 | )
17 |
18 | el = require('./mithril')(props)
19 | m.render(
20 | document.querySelector('#mithril')
21 | el
22 | )
23 |
24 | hg.app(
25 | document.querySelector('#mercury')
26 | hg.state({})
27 | -> require('./mercury')(props)
28 | )
29 |
--------------------------------------------------------------------------------
/example/runtimes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | minskl
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/example/runtimes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reiny-runtime-examples",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "coffeeify": "^1.0.0"
13 | },
14 | "dependencies": {
15 | "reiny": "file:../..",
16 | "deku": "^0.1.1",
17 | "extend": "^2.0.0",
18 | "mercury": "^14.0.0",
19 | "mithril": "^0.1.34",
20 | "virdy": "^0.3.0",
21 | "virtual-dom": "^2.0.1",
22 | "xtend": "^4.0.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/runtimes/template.reiny:
--------------------------------------------------------------------------------
1 | // props and inline style
2 | .main.container(
3 | data-id = 'this-is-id'
4 | ) {
5 | background-color: #eee
6 | width: 640px
7 | height: 300px
8 | font-size: 1em
9 | }
10 | // text
11 | h1 This is a title
12 | | expand with span
13 | span = @greeting
14 |
15 | // if syntax
16 | if false
17 | a hoge fuga aaa
18 |
19 | // inline expression
20 | if { 2 > 1 }
21 | a(key='fooo') hoge fuga aaa
22 |
23 | // for syntax
24 | ul
25 | for i in @items
26 | li item
27 |
28 | // object mixin as property
29 | - let o = {'data-a': 'aaa', 'data-b': 'bbb'};
30 | .foo(
31 | > o
32 | onClick = {- function(){console.log('foo')} -}
33 | )
34 |
--------------------------------------------------------------------------------
/example/template.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | module.exports = function(self) {
3 | var reiny = require('reiny/runtime');
4 | var __extend = reiny.xtend;
5 |
6 | if (self == null) self = {};
7 | return reiny.runtime(function($) {
8 | $('div', {
9 | 'data-id': 'this-is-id',
10 | 'style': {
11 | 'backgroundColor': '#eee',
12 | 'width': '640px',
13 | 'height': 40 * 12,
14 | 'fontSize': '1em'
15 | },
16 | 'ref': 'mainCotnainer',
17 | 'className': ['main', 'container'].join(" ")
18 | }, function() {
19 | $('h1', {}, 'This is a title');
20 | $('span', {}, 'expand with span');
21 | $('span', {}, self.greeting);
22 | if (false) {
23 | $('a', {}, 'hoge fuga aaa')
24 | };
25 | if (2 > 1) {
26 | $('a', {
27 | 'key': 'fooo'
28 | }, 'hoge fuga aaa')
29 | };
30 | $('ul', {}, function() {
31 | for (var __i in self.items) {
32 |
33 | var i = self.items[__i];
34 | $('li', {
35 | 'key': i
36 | }, i);;
37 | };
38 | });
39 | var o = {
40 | 'data-a': 'aaa',
41 | 'data-b': 'bbb'
42 | };;
43 | $('div', __extend({}, o, {
44 | 'onClick': function() {
45 | console.log('foo')
46 | },
47 | 'className': ['foo'].join(" ")
48 | }));
49 | var Foo = React.createClass({
50 | displayName: 'Foo',
51 |
52 | render: function render() {
53 | return React.createElement('div', {
54 | className: 'foo'
55 | });
56 | }
57 | });;
58 | $(Foo, {});
59 | var el = React.createElement(Foo, {});;
60 | $.direct(el);
61 | })
62 | }, {
63 | type: 'react'
64 | });
65 | }
--------------------------------------------------------------------------------
/example/template.reiny:
--------------------------------------------------------------------------------
1 | .main.container&mainCotnainer(
2 | data-id = 'this-is-id'
3 | ) {
4 | background-color: #eee
5 | width: 640px
6 | height: { 40 * 12 }
7 | font-size: 1em
8 | }
9 | h1 This is a title
10 | | expand with span
11 | span = @greeting
12 |
13 | // if syntax
14 | if false
15 | a hoge fuga aaa
16 |
17 | // inline expression
18 | if { 2 > 1 }
19 | a(key='fooo') hoge fuga aaa
20 |
21 | // for syntax
22 | ul
23 | for i in @items
24 | li(key=i) = i
25 |
26 | // object mixin as property
27 | - let o = {'data-a': 'aaa', 'data-b': 'bbb'};
28 | .foo(
29 | > o
30 | onClick = {- function(){console.log('foo')} -}
31 | )
32 |
33 | // mutli line code
34 | ---
35 | let Foo = React.createClass({
36 | render: () => {
37 | return React.createElement('div', {className: 'foo'});
38 | }
39 | })
40 | ---
41 | // CamelCase becomes element reference
42 | Foo()
43 |
44 | // Embed element direactly
45 | - var el = React.createElement(Foo, {})
46 | +(el)
47 |
--------------------------------------------------------------------------------
/grammars/_entry.pegcoffee:
--------------------------------------------------------------------------------
1 | // Indent Style Syntax
2 | {
3 | global.ctx = {}
4 | ctx.indentStack = []
5 | ctx.indent = ""
6 |
7 | global.buildTree = (first, rest, builder) ->
8 | result = first
9 | for i in rest
10 | result = builder result, i
11 | result
12 |
13 | global.buildBinaryExpression = (first, rest) ->
14 | buildTree first, rest, (result, element) ->
15 | {
16 | type: "BinaryExpression",
17 | operator: element[1]
18 | left: result
19 | right: element[3]
20 | }
21 |
22 | r = (node) ->
23 | node.raw = text().replace /[\uEFEF\uEFFE\uEFFF]/g, ''
24 | node
25 | # store position information
26 | p = (node) ->
27 | node.line = line()
28 | node.column = column()
29 | node.offset = offset()
30 | node
31 |
32 | # composition of r and p
33 | global.__rp = (node) -> r p node
34 |
35 | }
36 |
37 | start = self:program {
38 | global.ctx = {}
39 | ctx.indentStack = []
40 | ctx.indent = ""
41 | self
42 | }
43 |
44 | program = lines:topLevelLine* __blank { __rp type: 'program', body: lines}
45 |
46 | topLevelLine
47 | = SAMEDENT node:(!EOL s:topLevelStatement {s}) comment? EOL* {node}
48 |
49 | line
50 | = SAMEDENT node:(!EOL s:statement {s}) comment? EOL* {node}
51 |
52 | block = children: ( INDENT c:line* DEDENT { c }) {children}
53 |
54 | EOL = "\r\n" / "\n" / "\r"
55 |
56 | comment = '//' value:toTheEndOfLine EOL?
57 | {
58 | __rp({type: 'comment', value})
59 | }
60 |
61 | toTheEndOfLine = !comment text:$((!EOL .)+) {text}
62 |
63 | SAMEDENT
64 | = i:[ \t]* &{
65 | i.join('') is ctx.indent
66 | }
67 |
68 | INDENT
69 | = &(
70 | i:[ \t]+ &{
71 | i.length > ctx.indent.length
72 | }
73 | {
74 | ctx.indentStack.push(ctx.indent)
75 | ctx.indent = i.join("")
76 | }
77 | )
78 |
79 | DEDENT
80 | = {
81 | ctx.indent = ctx.indentStack.pop()
82 | }
83 |
84 | // Utils
85 | space = ' '
86 | _ = space*
87 | __ = space+
88 | __blank = $([ \n\t\r]*)
89 |
90 | symbol = $([a-zA-Z_] [a-zA-Z0-9_]*)
91 | dottableSymbol = $(symbol ('.' symbol)*)
92 | hyphenizableSymbol = $([a-zA-Z_-] [a-zA-Z0-9_-]*)
93 |
94 | reserved
95 | = SharedKeywords
96 | / JSKeywords
97 |
98 | SharedKeywords
99 | = ("true" / "false" / "null" / "this" / "new" / "delete" / "typeof" /
100 | "instanceof" / "in" / "return" / "throw" / "break" / "continue" / "debugger" /
101 | "if" / "else" / "switch" / "for" / "while" / "do" / "try" / "catch" /
102 | "finally" / "class" / "extends" / "super") !symbol
103 |
104 | JSKeywords
105 | = ("case" / "default" / "function" / "var" / "void" / "with" / "const" /
106 | "let" / "enum" / "export" / "import" / "native" / "implements" / "interface" /
107 | "package" / "private" / "protected" / "public" / "static" / "yield") !symbol
108 |
--------------------------------------------------------------------------------
/grammars/expression.pegcoffee:
--------------------------------------------------------------------------------
1 | //////////////
2 | // Expressions
3 | //////////////
4 |
5 | expr = primitive / embededExpr / identifier
6 | identifier = thisIdentifier / memberAccessableIdentifier / singleIdentifier
7 | singleIdentifier = !reserved symbol:symbol {__rp type: 'identifier', value: symbol}
8 | thisIdentifier = !reserved '@' s:dottableSymbol {__rp type:'thisIdentifier', value: s}
9 | memberAccessableIdentifier = !reserved symbol:dottableSymbol {__rp type: 'identifier', value: symbol}
10 |
11 | embededExpr
12 | = '{-' code:$((!'-}' .)*) '-}' {__rp type: 'embededExpr', value: code}
13 | / '{' code:$((!'}' .)*) '}' {__rp type: 'embededExpr', value: code}
14 |
15 | // binary expression
16 |
17 | /*
18 | LeftHandSideExpression
19 | = CallExpression
20 | / NewExpression
21 |
22 | PostfixExpression
23 | = argument:LeftHandSideExpression _ operator:PostfixOperator {
24 | {
25 | type: "UpdateExpression",
26 | operator: operator,
27 | argument: argument,
28 | prefix: false
29 | };
30 | }
31 | / LeftHandSideExpression
32 |
33 | PostfixOperator
34 | = "++"
35 | / "--"
36 |
37 | PrimaryExpression
38 | = "(" __ expression:Expression __ ")" { return expression; }
39 |
40 | UnaryExpression
41 | //= PostfixExpression
42 | = operator:UnaryOperator __ argument:UnaryExpression {
43 | type =
44 | if operator is "++" or operator is "--"
45 | "UpdateExpression"
46 | else
47 | "UnaryExpression"
48 |
49 | {
50 | type: type
51 | operator: operator
52 | argument: argument
53 | prefix: true
54 | }
55 | }
56 |
57 | UnaryOperator
58 | = $DeleteToken
59 | / $VoidToken
60 | / $TypeofToken
61 | / "++"
62 | / "--"
63 | / $("+" !"=")
64 | / $("-" !"=")
65 | / "~"
66 | / "!"
67 |
68 | MultiplicativeExpression
69 | = first:UnaryExpression
70 | rest:(__ MultiplicativeOperator __ UnaryExpression)*
71 | { buildBinaryExpression(first, rest)}
72 |
73 | MultiplicativeOperator
74 | = $("*" !"=")
75 | / $("/" !"=")
76 | / $("%" !"=")
77 |
78 | AdditiveExpression
79 | = first:MultiplicativeExpression
80 | rest:(__ AdditiveOperator __ MultiplicativeExpression)*
81 | { buildBinaryExpression(first, rest) }
82 |
83 | AdditiveOperator
84 | = $("+" ![+=])
85 | / $("-" ![-=])
86 |
87 | ShiftExpression
88 | = first:AdditiveExpression
89 | rest:(__ ShiftOperator __ AdditiveExpression)*
90 | { buildBinaryExpression(first, rest); }
91 |
92 | ShiftOperator
93 | = $("<<" !"=")
94 | / $(">>>" !"=")
95 | / $(">>" !"=")
96 |
97 | RelationalExpression
98 | = first:ShiftExpression
99 | rest:(__ RelationalOperator __ ShiftExpression)*
100 | { buildBinaryExpression(first, rest); }
101 |
102 | RelationalOperator
103 | = "<="
104 | / ">="
105 | / $("<" !"<")
106 | / $(">" !">")
107 | / $InstanceofToken
108 | / $InToken
109 |
110 | RelationalExpressionNoIn
111 | = first:ShiftExpression
112 | rest:(__ RelationalOperatorNoIn __ ShiftExpression)*
113 | { buildBinaryExpression(first, rest); }
114 |
115 | RelationalOperatorNoIn
116 | = "<="
117 | / ">="
118 | / $("<" !"<")
119 | / $(">" !">")
120 | / $InstanceofToken
121 |
122 | EqualityExpression
123 | = first:RelationalExpression
124 | rest:(__ EqualityOperator __ RelationalExpression)*
125 | { buildBinaryExpression(first, rest); }
126 |
127 | EqualityExpressionNoIn
128 | = first:RelationalExpressionNoIn
129 | rest:(__ EqualityOperator __ RelationalExpressionNoIn)*
130 | { buildBinaryExpression(first, rest); }
131 |
132 | EqualityOperator
133 | = "==="
134 | / "!=="
135 | / "=="
136 | / "!="
137 |
138 | BitwiseANDExpression
139 | = first:EqualityExpression
140 | rest:(__ BitwiseANDOperator __ EqualityExpression)*
141 | { buildBinaryExpression(first, rest); }
142 |
143 | BitwiseANDExpressionNoIn
144 | = first:EqualityExpressionNoIn
145 | rest:(__ BitwiseANDOperator __ EqualityExpressionNoIn)*
146 | { buildBinaryExpression(first, rest); }
147 |
148 | BitwiseANDOperator
149 | = $("&" ![&=])
150 |
151 | BitwiseXORExpression
152 | = first:BitwiseANDExpression
153 | rest:(__ BitwiseXOROperator __ BitwiseANDExpression)*
154 | { buildBinaryExpression(first, rest); }
155 |
156 | BitwiseXORExpressionNoIn
157 | = first:BitwiseANDExpressionNoIn
158 | rest:(__ BitwiseXOROperator __ BitwiseANDExpressionNoIn)*
159 | { buildBinaryExpression(first, rest); }
160 |
161 | BitwiseXOROperator
162 | = $("^" !"=")
163 |
164 | BitwiseORExpression
165 | = first:BitwiseXORExpression
166 | rest:(__ BitwiseOROperator __ BitwiseXORExpression)*
167 | { buildBinaryExpression(first, rest); }
168 |
169 | BitwiseORExpressionNoIn
170 | = first:BitwiseXORExpressionNoIn
171 | rest:(__ BitwiseOROperator __ BitwiseXORExpressionNoIn)*
172 | { buildBinaryExpression(first, rest); }
173 |
174 | BitwiseOROperator
175 | = $("|" ![|=])
176 |
177 | LogicalANDExpression
178 | = first:BitwiseORExpression
179 | rest:(__ LogicalANDOperator __ BitwiseORExpression)*
180 | { buildBinaryExpression(first, rest); }
181 |
182 | LogicalANDExpressionNoIn
183 | = first:BitwiseORExpressionNoIn
184 | rest:(__ LogicalANDOperator __ BitwiseORExpressionNoIn)*
185 | { buildBinaryExpression(first, rest); }
186 |
187 | LogicalANDOperator
188 | = "&&"
189 |
190 | LogicalORExpression
191 | = first:LogicalANDExpression
192 | rest:(__ LogicalOROperator __ LogicalANDExpression)*
193 | { buildBinaryExpression(first, rest); }
194 |
195 | LogicalORExpressionNoIn
196 | = first:LogicalANDExpressionNoIn
197 | rest:(__ LogicalOROperator __ LogicalANDExpressionNoIn)*
198 | { buildBinaryExpression(first, rest); }
199 |
200 | LogicalOROperator
201 | = "||"
202 |
203 | IdentifierPart = symbol
204 | // tokens
205 | BreakToken = "break" !IdentifierPart
206 | CaseToken = "case" !IdentifierPart
207 | CatchToken = "catch" !IdentifierPart
208 | ClassToken = "class" !IdentifierPart
209 | ConstToken = "const" !IdentifierPart
210 | ContinueToken = "continue" !IdentifierPart
211 | DebuggerToken = "debugger" !IdentifierPart
212 | DefaultToken = "default" !IdentifierPart
213 | DeleteToken = "delete" !IdentifierPart
214 | DoToken = "do" !IdentifierPart
215 | ElseToken = "else" !IdentifierPart
216 | EnumToken = "enum" !IdentifierPart
217 | ExportToken = "export" !IdentifierPart
218 | ExtendsToken = "extends" !IdentifierPart
219 | FalseToken = "false" !IdentifierPart
220 | FinallyToken = "finally" !IdentifierPart
221 | ForToken = "for" !IdentifierPart
222 | FunctionToken = "function" !IdentifierPart
223 | GetToken = "get" !IdentifierPart
224 | IfToken = "if" !IdentifierPart
225 | ImportToken = "import" !IdentifierPart
226 | InstanceofToken = "instanceof" !IdentifierPart
227 | InToken = "in" !IdentifierPart
228 | NewToken = "new" !IdentifierPart
229 | NullToken = "null" !IdentifierPart
230 | ReturnToken = "return" !IdentifierPart
231 | SetToken = "set" !IdentifierPart
232 | SuperToken = "super" !IdentifierPart
233 | SwitchToken = "switch" !IdentifierPart
234 | ThisToken = "this" !IdentifierPart
235 | ThrowToken = "throw" !IdentifierPart
236 | TrueToken = "true" !IdentifierPart
237 | TryToken = "try" !IdentifierPart
238 | TypeofToken = "typeof" !IdentifierPart
239 | VarToken = "var" !IdentifierPart
240 | VoidToken = "void" !IdentifierPart
241 | WhileToken = "while" !IdentifierPart
242 | WithToken = "with" !IdentifierPart
243 |
244 | */
245 |
--------------------------------------------------------------------------------
/grammars/primitive.pegcoffee:
--------------------------------------------------------------------------------
1 | // primitive.pegcoffee ===================
2 |
3 | primitive = boolean / number / string
4 |
5 | boolean = v:_boolean {__rp type: 'boolean', value: v}
6 | number = v:$(_number) {__rp type: 'number', value: v}
7 | string = value:_string
8 | {
9 | v = value.replace(/'/g, '').replace(/"/g, '')
10 | __rp type: 'string', value: v
11 | }
12 |
13 | // boolean
14 |
15 | _boolean = "true" / "false"
16 |
17 | // number
18 | _number
19 | = "0b" bs:$(bit+)
20 | / "0o" os:$(octalDigit+)
21 | / "0x" hs:$(hexDigit+)
22 | / base:decimal e:[eE] sign:[+-]? exponent:decimal
23 | / decimal
24 |
25 | decimal
26 | // trailing and leading radix points are discouraged anyway
27 | = integral:integer fractional:$("." decimalDigit+)?
28 |
29 | integer
30 | = "0"
31 | / $([1-9] decimalDigit*)
32 | decimalDigit = [0-9]
33 | hexDigit = [0-9a-fA-F]
34 | octalDigit = [0-7]
35 | bit = [01]
36 |
37 | // string
38 | _string
39 | = $("\"\"\"" d:(stringData / "'" / $("\"" "\""? !"\""))+ "\"\"\"")
40 | / $("'''" d:(stringData / "\"" / "#" / $("'" "'"? !"'"))+ "'''")
41 | / $("\"" d:(stringData / "'")* "\"")
42 | / $("'" d:(stringData / "\"" / "#")* "'")
43 | stringData
44 | = [^"'\\#]
45 | / UnicodeEscapeSequence
46 | / "\\x" h:$(hexDigit hexDigit) { String.fromCharCode parseInt h, 16 }
47 | / "\\0" !decimalDigit { '\0' }
48 | / "\\0" &decimalDigit { throw new SyntaxError ['string data'], 'octal escape sequence', offset(), line(), column() }
49 | / "\\b" { '\b' }
50 | / "\\t" { '\t' }
51 | / "\\n" { '\n' }
52 | / "\\v" { '\v' }
53 | / "\\f" { '\f' }
54 | / "\\r" { '\r' }
55 | / "\\" c:. { c }
56 | / c:"#" !"{" { c }
57 |
58 | // unicode
59 | UnicodeEscapeSequence = "\\u" h0:hexDigit h1:hexDigit h2:hexDigit h3:hexDigit { String.fromCharCode parseInt h0 + h1 + h2 + h3, 16 }
60 | UnicodeLetter = [\u0041-\u005A\u00C0-\u00D6\u00D8-\u00DE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0531-\u0556\u10A0-\u10C5\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uFF21-\uFF3A\u0061-\u007A\u00AA\u00B5\u00BA\u00DF-\u00F6\u00F8-\u00FF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0561-\u0587\u1D00-\u1D2B\u1D62-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7C\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2D00-\u2D25\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7FA\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A\u01C5\u01C8\u01CB\u01F2\u1F88-\u1F8F\u1F98-\u1F9F\u1FA8-\u1FAF\u1FBC\u1FCC\u1FFC\u02B0-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0374\u037A\u0559\u0640\u06E5\u06E6\u07F4\u07F5\u07FA\u081A\u0824\u0828\u0971\u0E46\u0EC6\u10FC\u17D7\u1843\u1AA7\u1C78-\u1C7D\u1D2C-\u1D61\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7D\u2D6F\u2E2F\u3005\u3031-\u3035\u303B\u309D\u309E\u30FC-\u30FE\uA015\uA4F8-\uA4FD\uA60C\uA67F\uA717-\uA71F\uA770\uA788\uA9CF\uAA70\uAADD\uFF70\uFF9E\uFF9F\u01BB\u01C0-\u01C3\u0294\u05D0-\u05EA\u05F0-\u05F2\u0620-\u063F\u0641-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u0800-\u0815\u0840-\u0858\u0904-\u0939\u093D\u0950\u0958-\u0961\u0972-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E45\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EDC\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10D0-\u10FA\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17DC\u1820-\u1842\u1844-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BC0-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C77\u1CE9-\u1CEC\u1CEE-\u1CF1\u2135-\u2138\u2D30-\u2D65\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3006\u303C\u3041-\u3096\u309F\u30A1-\u30FA\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400\u4DB5\u4E00\u9FCB\uA000-\uA014\uA016-\uA48C\uA4D0-\uA4F7\uA500-\uA60B\uA610-\uA61F\uA62A\uA62B\uA66E\uA6A0-\uA6E5\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA6F\uAA71-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB\uAADC\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF66-\uFF6F\uFF71-\uFF9D\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF] / "\uD82C" [\uDC00\uDC01] / "\uD808" [\uDC00-\uDF6E] / "\uD869" [\uDED6\uDF00] / "\uD809" [\uDC00-\uDC62] / "\uD835" [\uDC00-\uDC19\uDC34-\uDC4D\uDC68-\uDC81\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB5\uDCD0-\uDCE9\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD38\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD6C-\uDD85\uDDA0-\uDDB9\uDDD4-\uDDED\uDE08-\uDE21\uDE3C-\uDE55\uDE70-\uDE89\uDEA8-\uDEC0\uDEE2-\uDEFA\uDF1C-\uDF34\uDF56-\uDF6E\uDF90-\uDFA8\uDFCA\uDC1A-\uDC33\uDC4E-\uDC54\uDC56-\uDC67\uDC82-\uDC9B\uDCB6-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDCEA-\uDD03\uDD1E-\uDD37\uDD52-\uDD6B\uDD86-\uDD9F\uDDBA-\uDDD3\uDDEE-\uDE07\uDE22-\uDE3B\uDE56-\uDE6F\uDE8A-\uDEA5\uDEC2-\uDEDA\uDEDC-\uDEE1\uDEFC-\uDF14\uDF16-\uDF1B\uDF36-\uDF4E\uDF50-\uDF55\uDF70-\uDF88\uDF8A-\uDF8F\uDFAA-\uDFC2\uDFC4-\uDFC9\uDFCB] / "\uD804" [\uDC03-\uDC37\uDC83-\uDCAF] / "\uD800" [\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1E\uDF30-\uDF40\uDF42-\uDF49\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDD40-\uDD74\uDF41\uDF4A\uDFD1-\uDFD5] / "\uD80C" [\uDC00-\uDFFF] / "\uD801" [\uDC00-\uDC9D] / "\uD86E" [\uDC1D] / "\uD803" [\uDC00-\uDC48] / "\uD840" [\uDC00] / "\uD87E" [\uDC00-\uDE1D] / "\uD86D" [\uDF34\uDF40] / "\uD81A" [\uDC00-\uDE38] / "\uD802" [\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDD00-\uDD15\uDD20-\uDD39\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72] / "\uD80D" [\uDC00-\uDC2E]
61 | UnicodeCombiningMark = [\u0300-\u036F\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0900-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0CBC\u0CBF\u0CC6\u0CCC\u0CCD\u0CE2\u0CE3\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1DC0-\u1DE6\u1DFC-\u1DFF\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F\uA67C\uA67D\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE26\u0903\u093B\u093E-\u0940\u0949-\u094C\u094E\u094F\u0982\u0983\u09BE-\u09C0\u09C7\u09C8\u09CB\u09CC\u09D7\u0A03\u0A3E-\u0A40\u0A83\u0ABE-\u0AC0\u0AC9\u0ACB\u0ACC\u0B02\u0B03\u0B3E\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0B57\u0BBE\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD7\u0C01-\u0C03\u0C41-\u0C44\u0C82\u0C83\u0CBE\u0CC0-\u0CC4\u0CC7\u0CC8\u0CCA\u0CCB\u0CD5\u0CD6\u0D02\u0D03\u0D3E-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D57\u0D82\u0D83\u0DCF-\u0DD1\u0DD8-\u0DDF\u0DF2\u0DF3\u0F3E\u0F3F\u0F7F\u102B\u102C\u1031\u1038\u103B\u103C\u1056\u1057\u1062-\u1064\u1067-\u106D\u1083\u1084\u1087-\u108C\u108F\u109A-\u109C\u17B6\u17BE-\u17C5\u17C7\u17C8\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u19B0-\u19C0\u19C8\u19C9\u1A19-\u1A1B\u1A55\u1A57\u1A61\u1A63\u1A64\u1A6D-\u1A72\u1B04\u1B35\u1B3B\u1B3D-\u1B41\u1B43\u1B44\u1B82\u1BA1\u1BA6\u1BA7\u1BAA\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1C24-\u1C2B\u1C34\u1C35\u1CE1\u1CF2\uA823\uA824\uA827\uA880\uA881\uA8B4-\uA8C3\uA952\uA953\uA983\uA9B4\uA9B5\uA9BA\uA9BB\uA9BD-\uA9C0\uAA2F\uAA30\uAA33\uAA34\uAA4D\uAA7B\uABE3\uABE4\uABE6\uABE7\uABE9\uABEA\uABEC] / "\uDB40" [\uDD00-\uDDEF] / "\uD834" [\uDD67-\uDD69\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44\uDD65\uDD66\uDD6D-\uDD72] / "\uD804" [\uDC01\uDC38-\uDC46\uDC80\uDC81\uDCB3-\uDCB6\uDCB9\uDCBA\uDC00\uDC02\uDC82\uDCB0-\uDCB2\uDCB7\uDCB8] / "\uD800" [\uDDFD] / "\uD802" [\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F]
62 | UnicodeDigit = [\u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19] / "\uD835" [\uDFCE-\uDFFF] / "\uD804" [\uDC66-\uDC6F] / "\uD801" [\uDCA0-\uDCA9]
63 | UnicodeConnectorPunctuation = [\u005F\u203F\u2040\u2054\uFE33\uFE34\uFE4D-\uFE4F\uFF3F]
64 | ZWNJ = "\u200C"
65 | ZWJ = "\u200D"
66 |
--------------------------------------------------------------------------------
/grammars/statement.pegcoffee:
--------------------------------------------------------------------------------
1 | //////////////////
2 | // Statements
3 | //////////////////
4 |
5 | topLevelStatement
6 | = propTypeDeclaration
7 | / statement
8 |
9 | statement
10 | = forStatement
11 | / ifStatement
12 | / element
13 | / directElement
14 | / code
15 | / multilineCode
16 | / textStatement
17 |
18 | ifStatement = 'if' __ condition:expr _ EOL children:block consequent:_elseIf* _else:_else?
19 | { __rp
20 | type: 'if'
21 | condition: condition
22 | consequents: consequent
23 | alternate: _else
24 | body: children
25 | }
26 |
27 | _elseIf = SAMEDENT 'else' __ 'if' __ condition:expr _ EOL children:block
28 | { __rp type: 'consequent', condition:condition, body:children}
29 | _else = SAMEDENT 'else' _ EOL children:block
30 | { __rp type: 'aliternate', body:children}
31 |
32 | forStatement =
33 | 'for' __ left:singleIdentifier second:(_ ',' _ i:singleIdentifier {i})?
34 | __ forType:('in'/'of')
35 | __ right:expr EOL children:block
36 | { __rp
37 | type: if forType is 'in' then 'forIn' else 'forOf'
38 | left: left
39 | second: second
40 | right: right
41 | body: children
42 | }
43 |
44 | textStatement = '|' _ text:toTheEndOfLine { __rp type: 'text', value: text}
45 |
46 | directElement = '+(' _ symbol:dottableSymbol _ ')'
47 | {
48 | __rp type: 'directElement', value: symbol
49 | }
50 |
51 | element
52 | = '=' _ expr:expr
53 | {
54 | __rp
55 | type: 'text'
56 | value: expr
57 | }
58 | / s:assignable props:props? _ styles:styles? _ children: _elementChildren?
59 | {
60 | __rp {type: 'element', value: s, children, props, styles}
61 | }
62 |
63 | _elementChildren
64 | = EOL INDENT c:line* DEDENT { c }
65 | / !EOL _ !'=' __ text:toTheEndOfLine { __rp {type: 'inlineText', value: text}}
66 | / !EOL _ '=' __ expr: expr {expr}
67 | assignable
68 | =
69 | elementName:singleIdentifier modifiers:modifier*
70 | {
71 | __rp {
72 | type: 'element'
73 | elementType: elementName.value
74 | modifiers: modifiers
75 | }
76 | }
77 | /
78 | modifiers:modifier+
79 | {
80 | __rp {
81 | type: 'element'
82 | elementType: 'div'
83 | modifiers: modifiers
84 | }
85 | }
86 | modifier = className / id / ref
87 | className = '.' className:hyphenizableSymbol { __rp type: 'className', value:className}
88 | id = '#' id:hyphenizableSymbol { __rp type: 'id', value: id}
89 | ref = '&' ref:hyphenizableSymbol { __rp type: 'ref', value: ref}
90 | key = ':' ref:hyphenizableSymbol { __rp type: 'key', value: ref}
91 |
92 | props = "(" __blank props:(p:property __blank {p})* ")"
93 | {
94 | __rp
95 | type: 'props'
96 | children: props
97 | }
98 |
99 | property
100 | = key:hyphenizableSymbol _ '=' _ expr: expr
101 | {
102 | __rp
103 | type: 'property'
104 | key: key
105 | expr: expr
106 | }
107 | / '>' _ key:dottableSymbol
108 | {
109 | __rp
110 | type: 'mergeable-object'
111 | key: key
112 | }
113 |
114 | styles = "{" __blank props:(p:_styleProperty __blank {p})* "}"
115 | {
116 | __rp
117 | type: 'styles'
118 | children: props
119 | }
120 |
121 | _styleProperty
122 | = key:hyphenizableSymbol _ ('='/':') _ expr:_styleExpr _ ';'?
123 | {
124 | __rp
125 | type: 'property'
126 | key: key
127 | expr: expr
128 | }
129 | / '>' _ key:dottableSymbol
130 | {
131 | __rp
132 | type: 'mergeable-object'
133 | key: key
134 | }
135 |
136 | _styleExpr = _stylableValue / expr
137 | _stylableValue = _suffixedValue / _colorValue
138 |
139 | _suffixedValue = v:$(number ('px' / 'em' / 'ex' / 'rem' / 'cm' / 'mm' / 'in' / 'pt' / 'pc' / '%'))
140 | { __rp type: 'string', value: v}
141 | _colorValue = v:(
142 | $(
143 | '#' [0-9a-fA-F]+)
144 | / 'rgb(' _ _colorInlineValue _ ',' _ _colorInlineValue _ ',' _ _colorInlineValue _ ')'
145 | / 'rgba(' _ _colorInlineValue _ ',' _ _colorInlineValue _ ',' _ _colorInlineValue _ ',' _ _colorInlineValue _ ')'
146 | )
147 | { __rp type: 'string', value: v}
148 |
149 | _colorInlineValue = $([0-9a-f]+) / $(integer '%')
150 | // TODO color code
151 |
152 | code = '-' space+ value:toTheEndOfLine
153 | {
154 | __rp {type: 'code', value}
155 | }
156 |
157 | multilineCode = _multilineCodeLeader EOL code:$((!_multilineCodeLeader .)*) _multilineCodeLeader
158 | {
159 | __rp {type: 'multilineCode', value:code}
160 | }
161 | _multilineCodeLeader = '---'
162 |
163 | propTypeDeclaration = '@' type:typeDeclaration {__rp type: 'propTypeDeclaration', value: type}
164 | typeDeclaration = symbol:symbol _ ':' _ expr:_propTypeExpr
165 | {__rp type: 'typeDeclaration', propertyName:symbol, typeExpr: expr}
166 | _propTypeExpr = typeName:$(symbol) + isArray:'[]'? optional:'?'?
167 | {__rp type: 'typeExpr', typeName:typeName, isArray: isArray?, optional: optional?}
168 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reiny",
3 | "version": "0.5.3",
4 | "description": "Template engine for React",
5 | "main": "lib/runtime",
6 | "bin": {
7 | "reiny": "reiny"
8 | },
9 | "scripts": {
10 | "prepublish": "./script/build",
11 | "test": "$(npm bin)/coffee test/test.coffee"
12 | },
13 | "author": "mizchi",
14 | "license": "MIT",
15 | "dependencies": {
16 | "babel-core": "^5.1.7",
17 | "camelize": "^1.0.0",
18 | "js-beautify": "^1.5.5",
19 | "minimist": "^1.1.1",
20 | "sass-convert": "^0.5.0",
21 | "pegjs": "^0.8.0",
22 | "pegjs-coffee-plugin": "^0.2.2",
23 | "strip-comments": "^0.3.2",
24 | "virdy": "^0.3.1",
25 | "xtend": "^4.0.0"
26 | },
27 | "devDependencies": {
28 | "browserify": "^9.0.8",
29 | "coffee-script": "^1.9.1",
30 | "espower-coffee": "^0.10.0",
31 | "js-beautify": "^1.5.5",
32 | "mkdirp": "^0.5.0",
33 | "power-assert": "^0.10.2",
34 | "react": "git+https://github.com/facebook/react#3c174cacc9428a7d5bf9cc31624010c0004bfc73",
35 | "sass-convert": "^0.5.0"
36 | },
37 | "directories": {
38 | "example": "example",
39 | "test": "test"
40 | },
41 | "repository": {
42 | "type": "git",
43 | "url": "https://github.com/mizchi/reiny.git"
44 | },
45 | "keywords": [
46 | "react",
47 | "template",
48 | "jade",
49 | "reiny",
50 | "mithril",
51 | "mercury"
52 | ],
53 | "bugs": {
54 | "url": "https://github.com/mizchi/reiny/issues"
55 | },
56 | "homepage": "https://github.com/mizchi/reiny"
57 | }
58 |
--------------------------------------------------------------------------------
/reiny:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('./lib/cli');
3 |
--------------------------------------------------------------------------------
/script/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | $(npm bin)/coffee -o lib -c src/*.coffee
3 |
--------------------------------------------------------------------------------
/script/build-parser:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env coffee
2 |
3 | PEG = require 'pegjs'
4 | coffee = require 'pegjs-coffee-plugin'
5 | path = require 'path'
6 | fs = require 'fs'
7 |
8 | # Run
9 | grammarFiles = [
10 | '../src/grammars/_entry.pegcoffee'
11 | '../src/grammars/statement.pegcoffee'
12 | '../src/grammars/expression.pegcoffee'
13 | '../src/grammars/primitive.pegcoffee'
14 | ]
15 |
16 | getGrammarSource = ->
17 | grammarFiles
18 | .map (fname) ->
19 | fs.readFileSync(path.join __dirname, fname).toString()
20 | .join('\n')
21 |
22 | grammar = getGrammarSource()
23 | fs.writeFileSync((path.join __dirname, '../grammar.pegcoffee'), grammar)
24 | try
25 | parser = PEG.buildParser grammar, plugins: [coffee]
26 | result = 'module.exports = ' + parser.parse.toString()
27 | fs.writeFileSync((path.join __dirname, '../parser.js'), result)
28 | console.log 'write done'
29 | catch e
30 | throw e
31 |
--------------------------------------------------------------------------------
/src/cli.coffee:
--------------------------------------------------------------------------------
1 | reiny = require('../lib/index')
2 | {inspect} = require('util')
3 | path = require('path')
4 | fs =require('fs')
5 |
6 | argv = require('minimist')(process.argv.slice(2))
7 |
8 | printBeautifiedCode = (source, options = {}) ->
9 | code = reiny.compile source, options
10 |
11 | printAst = (source, options = {}) ->
12 | code = reiny.parse source, options
13 | inspect code, depth: null
14 |
15 | [target] = argv._
16 |
17 | {execSync} = require 'child_process'
18 | run = (target, argv) ->
19 | targetPath = path.join process.cwd(), target
20 | source = fs.readFileSync(targetPath).toString()
21 | code =
22 | if argv.scss
23 | styleCompiler = require '../lib/style-compiler'
24 | ast = reiny.parse source
25 | styleCompiler ast
26 | else
27 | # compile
28 | reiny.compile source, argv
29 |
30 | # TODO: auto generate filename by extname
31 | if argv.out or argv.o
32 | # console.log process.cwd(), argv.out ? argv.o
33 | outputPath = path.join process.cwd(), (argv.out ? argv.o)
34 | fs.writeFileSync(outputPath, code)
35 | else
36 | console.log code
37 |
38 | run(argv._[0], argv)
39 |
--------------------------------------------------------------------------------
/src/compiler.coffee:
--------------------------------------------------------------------------------
1 | # postprocess
2 | Babel = require "babel-core"
3 | camelize = require 'camelize'
4 |
5 | transformCode = (code) ->
6 | Babel.transform(code)
7 | .code
8 | .replace('\"use strict\";\n', '')
9 | .replace('\'use strict\';\n', '')
10 |
11 | buildProps = (node) ->
12 | obj = {}
13 | classNames = []
14 |
15 | if node.props?
16 | obj.__mergeables = node.props.children.filter (p) -> p.type is 'mergeable-object'
17 |
18 | props = node.props.children.filter (p) -> p.type is 'property'
19 | for i in props
20 | if i.key is 'className'
21 | classNames.push i.expr
22 | else
23 | obj[i.key] = _compile(i.expr)
24 |
25 | # style
26 | if node.styles?
27 | style = {}
28 | for s in node.styles.children
29 | # camelize for react style
30 | style[camelize s.key] = _compile(s.expr)
31 | obj.style = style
32 |
33 | # classes and id
34 | if node.value?.modifiers?
35 | for m in node.value.modifiers
36 | switch m.type
37 | when 'className' then classNames.push {type:'string', value: m.value}
38 | when 'id' then obj.id = '\'' + m.value + '\''
39 | when 'ref' then obj.ref = '\'' + m.value + '\''
40 | when 'key' then obj.key = '\'' + m.value + '\''
41 | if classNames.length > 0
42 | code = classNames
43 | .map((e) -> _compile(e))
44 | .join(',')
45 | obj.className = '[' + code + '].join(" ")'
46 | obj
47 |
48 | _wrapStr = (s) -> '\'' + s + '\''
49 | expandObj = (obj) ->
50 | kv =
51 | for k, v of obj when k not in ['__mergeables']
52 | if v instanceof Object
53 | _wrapStr(k) + ': ' + expandObj(v)
54 | else
55 | _wrapStr(k) + ':' + v
56 | ret = '{' + kv.join(',') + '}'
57 | if obj.__mergeables?.length
58 | objs = obj.__mergeables
59 | .map((m) -> m.key)
60 | .join(',')
61 | "__extend({}, #{objs}, #{ret})"
62 | else
63 | ret
64 |
65 | isUpperCase = (text) ->
66 | text.toUpperCase() is text
67 |
68 | buildPropTypes = (propTypeLines) ->
69 | propTypes = {}
70 | for propType in propTypeLines
71 | # console.error "key", propType
72 | propertyName = propType.value.propertyName
73 | typeName = propType.value.typeExpr.typeName
74 | typeCode =
75 | if propType.value.typeExpr.isArray
76 | "_T.arrayOf(_T.#{typeName})"
77 | else
78 | "_T.#{typeName}"
79 |
80 | unless propType.value.typeExpr.optional
81 | typeCode += ".isRequired"
82 |
83 | propTypes[propertyName] = typeCode
84 |
85 | # console.error propTypes
86 | # console.error expandObj propTypes
87 | expandObj propTypes
88 |
89 | _compile = (node) ->
90 | switch node.type
91 | when 'directElement'
92 | "$.direct(#{node.value})"
93 |
94 | when 'element'
95 | props = buildProps(node)
96 | propsStr = expandObj props
97 | elementCode =
98 | if isUpperCase(node.value.elementType[0])
99 | _compile(type:'identifier', value:node.value.elementType)
100 | else
101 | _compile(type:'string', value:node.value.elementType)
102 |
103 | unless node.children
104 | return "$(#{elementCode}, #{propsStr})"
105 |
106 | if node.children.type in ['identifier', 'boolean', 'number', 'string', 'inlineText', 'embededExpr','thisIdentifier']
107 | return "$(#{elementCode}, #{propsStr}, #{_compile node.children})"
108 |
109 | children = node.children?.map (child) -> _compile(child)
110 | childrenCode = 'function(){' + (children?.join(';') ? '') + ';}'
111 | "$(#{elementCode}, #{propsStr}, #{childrenCode})"
112 |
113 | when 'code'
114 | transformCode node.value
115 |
116 | when 'multilineCode'
117 | transformCode node.value
118 |
119 | when 'embededExpr'
120 | node.value
121 |
122 | when 'free'
123 | node.value
124 |
125 | when 'propTypeDeclaration'
126 | throw 'propTypeDeclaration is only allowed on toplevel'
127 |
128 | when 'if'
129 | condCode = _compile node.condition
130 |
131 | children = node.body.map (child) -> _compile(child)
132 | childrenCode = children.join(';')
133 |
134 | ifCode = """
135 | if(#{condCode}) { #{childrenCode} }
136 | """
137 |
138 | if node.consequents?.length
139 | for consequent in node.consequents
140 | consequentCondCode = _compile consequent.condition
141 | consequentCode =
142 | consequent.body
143 | .map((child) -> _compile(child))
144 | .join(';')
145 |
146 | ifCode += "else if(#{consequentCondCode}) { #{consequentCode} }"
147 |
148 | if node.alternate?
149 | alternateChildrenCode =
150 | node.alternate.body
151 | .map((child) -> _compile(child))
152 | .join(';')
153 | ifCode += "else { #{alternateChildrenCode} }"
154 |
155 | ifCode
156 |
157 | when 'forIn'
158 | bodyCode = node.body
159 | .map((c) -> _compile(c) + ';')
160 | .join('')
161 | """
162 | for(var __i in #{_compile node.right}) {
163 | #{if node.second? then "var #{node.second.value} = __i;" else ""}
164 | var #{node.left.value} = #{_compile node.right}[__i];
165 | #{bodyCode};
166 | }
167 | """
168 |
169 | when 'forOf'
170 | bodyCode = node.body
171 | .map((c) -> _compile(c) + ';')
172 | .join('')
173 | """
174 | for(var __i in #{_compile node.right}) {
175 | #{if node.second? then "var #{node.second.value} = __i;" else ""}
176 | var #{node.left.value} = #{_compile node.right}[__i];
177 | #{bodyCode};
178 | }
179 | """
180 |
181 | when 'comment'
182 | "/* #{node.value} */"
183 |
184 | when 'text'
185 | # "$('span', {}, '#{node.value}')"
186 | code =
187 | if typeof node.value is 'string'
188 | _wrapStr node.value
189 | else
190 | _compile(node.value)
191 |
192 | "$.text(#{code})"
193 |
194 | when 'inlineText'
195 | "\'#{node.value}\'"
196 |
197 | when 'string'
198 | "\'#{node.value}\'"
199 | when 'number'
200 | "#{node.value}"
201 | when 'boolean'
202 | "#{node.value}"
203 | when 'identifier'
204 | node.value
205 | when 'thisIdentifier'
206 | "self\.#{node.value}"
207 | else
208 | throw 'unknow node: ' + node.type
209 |
210 | # ProgramNode => string
211 | module.exports = (node, options = {}) ->
212 | exportTarget = options.export ? 'module.exports'
213 | codes = node.body
214 | .filter((n) -> n.type isnt 'propTypeDeclaration')
215 | .map((n) -> _compile(n))
216 |
217 | propTypes = node.body.filter (n) -> n.type is 'propTypeDeclaration'
218 | propTypesCode = propTypes
219 | .map((propType) -> 'var ' + propType.value.propertyName + ' = self.' + propType.value.propertyName + ';')
220 | .join('\n')
221 |
222 | result = """
223 | "use strict";
224 | #{exportTarget} = function(self) {
225 | var reiny = require('reiny');
226 | var __extend = reiny.xtend;
227 | if(self == null) self = {};
228 | #{propTypesCode}
229 | return reiny.runtime(function($){
230 | #{codes.join('\n')}
231 | }, {target: '#{options.target ? 'react'}'});
232 | }
233 | """
234 |
235 | if propTypes.length > 0
236 | result += '\nvar _T = React.PropTypes;\nmodule.exports.propTypes =' + buildPropTypes(propTypes)
237 |
238 | result
239 |
--------------------------------------------------------------------------------
/src/format-error.coffee:
--------------------------------------------------------------------------------
1 | COLOURS =
2 | red: '\x1B[31m'
3 | green: '\x1B[32m'
4 | yellow: '\x1B[33m'
5 | blue: '\x1B[34m'
6 | magenta: '\x1B[35m'
7 | cyan: '\x1B[36m'
8 |
9 | numberLines = (input, startLine = 1) ->
10 | lines = input.split '\n'
11 | padSize = "#{lines.length + startLine - 1}".length
12 | numbered = for line, i in lines
13 | currLine = "#{i + startLine}"
14 | pad = ((Array padSize + 1).join '0')[currLine.length..]
15 | "#{pad}#{currLine} : #{lines[i]}"
16 | numbered.join '\n'
17 |
18 | SUPPORTS_COLOUR =
19 | process?.stderr?.isTTY and not process.env.NODE_DISABLE_COLORS
20 | humanReadable = (str) ->
21 | ((str.replace /\uEFEF/g, '(INDENT)').replace /\uEFFE/g, '(DEDENT)').replace /\uEFFF/g, '(TERM)'
22 | colourise = (colour, str) ->
23 | if SUPPORTS_COLOUR then "#{COLOURS[colour]}#{str}\x1B[39m" else str
24 |
25 | cleanMarkers = (str) -> str.replace /[\uEFEF\uEFFE\uEFFF]/g, ''
26 |
27 | pointToErrorLocation = (source, line, column, numLinesOfContext = 3) ->
28 |
29 | lines = source.split '\n'
30 | lines.pop() unless lines[lines.length - 1]
31 | # figure out which lines are needed for context
32 | currentLineOffset = line - 1
33 | startLine = currentLineOffset - numLinesOfContext
34 | if startLine < 0 then startLine = 0
35 | # get the context lines
36 | preLines = lines[startLine..currentLineOffset]
37 | preLines[preLines.length - 1] = colourise 'yellow', preLines[preLines.length - 1]
38 | postLines = lines[currentLineOffset + 1 .. currentLineOffset + numLinesOfContext]
39 | numberedLines = (numberLines (cleanMarkers [preLines..., postLines...].join '\n'), startLine + 1).split '\n'
40 | preLines = numberedLines[0...preLines.length]
41 | postLines = numberedLines[preLines.length...]
42 | # set the column number to the position of the error in the cleaned string
43 | column = (cleanMarkers "#{lines[currentLineOffset]}\n"[...column]).length
44 | padSize = ((currentLineOffset + 1 + postLines.length).toString 10).length
45 | [
46 | preLines...
47 | "#{colourise 'red', (Array padSize + 1).join '^'} : #{(Array column).join ' '}#{colourise 'red', '^'}"
48 | postLines...
49 | ].join '\n'
50 |
51 | formatParserError = (input, e) ->
52 | realColumn = (cleanMarkers "#{(input.split '\n')[e.line - 1]}\n"[...e.column]).length
53 | unless e.found?
54 | return "Syntax error on line #{e.line}, column #{realColumn}: unexpected end of input"
55 | found = JSON.stringify humanReadable e.found
56 | found = ((found.replace /^"|"$/g, '').replace /'/g, '\\\'').replace /\\"/g, '"'
57 | unicode = ((e.found.charCodeAt 0).toString 16).toUpperCase()
58 | unicode = "\\u#{"0000"[unicode.length..]}#{unicode}"
59 | message = "Syntax error on line #{e.line}, column #{realColumn}: unexpected '#{found}' (#{unicode})"
60 | # message
61 | "#{message}\n#{pointToErrorLocation input, e.line, realColumn}"
62 |
63 | module.exports = formatParserError
64 |
--------------------------------------------------------------------------------
/src/index.coffee:
--------------------------------------------------------------------------------
1 | {js_beautify} = require('js-beautify')
2 | PEG = require 'pegjs'
3 | coffee = require 'pegjs-coffee-plugin'
4 | fs = require 'fs'
5 | path = require 'path'
6 |
7 | # Run
8 | grammarFiles = [
9 | '../grammars/_entry.pegcoffee'
10 | '../grammars/statement.pegcoffee'
11 | '../grammars/expression.pegcoffee'
12 | '../grammars/primitive.pegcoffee'
13 | ]
14 |
15 | getGrammarSource = ->
16 | grammarFiles
17 | .map((fname) ->
18 | fs.readFileSync(path.join __dirname, fname).toString()
19 | )
20 | .join('\n')
21 |
22 | grammar = getGrammarSource()
23 | parser = PEG.buildParser grammar, plugins: [coffee]
24 |
25 | # string => AST
26 | exports.parse = parse = (source, options = {}) ->
27 | preprocess = require './preprocess'
28 | preprocessed = preprocess source
29 | try
30 | return parser.parse preprocessed, options
31 | catch e
32 | formatter = require('./format-error')
33 | throw new Error (formatter source, e)
34 |
35 | # AST => string
36 | exports._compile = _compile = (ast, options = {}) ->
37 | compile = require './compiler'
38 | js_beautify(compile(ast, options))
39 |
40 | # string => string
41 | exports.compile = (source, options = {}) ->
42 | ast = parse(source, options)
43 | _compile(ast, options)
44 |
--------------------------------------------------------------------------------
/src/preprocess.coffee:
--------------------------------------------------------------------------------
1 | stripComments = require 'strip-comments'
2 | module.exports = (text) ->
3 | code = stripComments(text)
4 | .split('\n')
5 | .filter (line) ->
6 | trimed = line.split( /\t|\s/ ).join('')
7 | trimed.length > 0 and (trimed.indexOf('//') isnt 0)
8 | .join('\n')
9 | code
10 |
--------------------------------------------------------------------------------
/src/runtime.coffee:
--------------------------------------------------------------------------------
1 | runtime = (block, options = {}) ->
2 | switch options.target ? 'react'
3 | when 'react' then require('virdy/runtime/react')(block, options)
4 | when 'mithril' then require('virdy/runtime/mithril')(block, options)
5 | when 'mercury' then require('virdy/runtime/mercury')(block, options)
6 | when 'deku' then require('virdy/runtime/deku')(block, options)
7 |
8 | module.exports = runtime
9 | module.exports.runtime = runtime
10 | runtime.xtend = xtend = require 'xtend'
11 |
12 | # createReactComponent(template:(props:Object) => ReactElement, ...mixins): ReactComponent
13 | #
14 | # Example.
15 | # Component = reiny.createReactComponent require('./template'),
16 | # onClick: -> console.log 'cliced'
17 | runtime.createReactComponent = (template, mixins...) ->
18 | React.createClass xtend({},
19 | propTypes: template.propTypes
20 | render: -> template(xtend {}, @, @props)
21 | , mixins...)
22 |
--------------------------------------------------------------------------------
/src/style-compiler.coffee:
--------------------------------------------------------------------------------
1 | buildStyles = (node) ->
2 | if node.styles?
3 | style = {}
4 | for s in node.styles.children
5 | style[s.key] = parse(s.expr)
6 | style
7 | else
8 | {}
9 |
10 | buildSelectors = (node) ->
11 | selectors = []
12 | if node.value?.modifiers?.length
13 | for m in node.value.modifiers
14 | switch m.type
15 | when 'className'
16 | selectors.push '.' + m.value
17 | when 'id'
18 | selectors.push '#' + m.value
19 | else
20 | selectors.push node.value.elementType
21 | selectors
22 |
23 | flatten = (listable) ->
24 | children = listable.map (child) -> parse(child)
25 | list = children.filter (i) -> i.type isnt 'para'
26 | for c in children when c.type is 'para'
27 | if c.children?
28 | list.push c.children...
29 | list
30 |
31 | parse = (node) ->
32 | switch node.type
33 | when 'program'
34 | codes = node.body
35 | .map (n) -> parse(n)
36 | codes
37 |
38 | when 'element'
39 | styles = buildStyles(node)
40 | selectors = buildSelectors(node)
41 | if node.children instanceof Array
42 | list = flatten(node.children)
43 | {selector: selectors.join(''), styles, children:list}
44 | else
45 | {selector: selectors.join(''), styles}
46 |
47 | when 'if'
48 | list = [].concat(
49 | flatten(node.body)
50 | ).concat(
51 | if node.consequents?.length
52 | _l = []
53 | node.consequents.forEach (consequent) ->
54 | _l = _l.concat(flatten consequent.body)
55 | _l
56 | else
57 | []
58 | ).concat(
59 | if node.alternate?
60 | flatten(node.alternate.body)
61 | else
62 | []
63 | )
64 | {type: 'para', children:list}
65 |
66 | when 'forIn', 'forOf'
67 | list = flatten(node.body)
68 | {type: 'para', children:list}
69 |
70 | when 'string'
71 | "#{node.value}"
72 | when 'number'
73 | "#{node.value}"
74 | when 'identifier'
75 | '$' + node.value
76 | when 'thisIdentifier'
77 | '$' + node.value
78 | else
79 | null
80 |
81 | serializeCSS = (node, parentSelector = '') ->
82 | selector = parentSelector + '' + node.selector
83 | styles = ''
84 | for k, v of node.styles
85 | styles += ' ' + k + ':' + v + ';\n'
86 | code = """
87 | #{selector} {
88 | #{styles}
89 | }
90 | """
91 | if node.children
92 | children = node.children
93 | .map (n) -> serializeCSS(n, selector)
94 | .join('\n')
95 | else
96 | children = ''
97 | code + '\n' + children
98 |
99 | serializeSCSS = (node, prefix = '') ->
100 | selector = node.selector
101 | styles = []
102 | for k, v of node.styles
103 | styles.push prefix + ' ' + k + ':' + v + ';'
104 | if node.children
105 | children = node.children
106 | .map (n) -> serializeSCSS(n, prefix + ' ')
107 | .join('\n')
108 | styles.push children
109 | """
110 | #{prefix}#{selector} {
111 | #{styles.join('\n')}
112 | #{prefix}}
113 | """
114 |
115 | module.exports = compile = (node, options = {}) ->
116 | lines = parse(node)
117 |
118 | if lines?.length
119 | lines.map((node) -> serializeSCSS node).join('\n')
120 | else
121 | ''
122 |
--------------------------------------------------------------------------------
/test/broken/identifier.reiny:
--------------------------------------------------------------------------------
1 | if for
2 |
--------------------------------------------------------------------------------
/test/broken/top-level-statement.reiny:
--------------------------------------------------------------------------------
1 | @a: number
2 | a
3 | @b: number
4 |
--------------------------------------------------------------------------------
/test/fixtures/binary.reiny:
--------------------------------------------------------------------------------
1 | span = 1*1
2 |
--------------------------------------------------------------------------------
/test/fixtures/child-type.reiny:
--------------------------------------------------------------------------------
1 | ---
2 | var Foo = React.createClass({
3 | render: function(){
4 | return React.createElement('div', {className: 'foo'});
5 | }
6 | })
7 | ---
8 |
9 | Foo()
10 |
--------------------------------------------------------------------------------
/test/fixtures/classname.reiny:
--------------------------------------------------------------------------------
1 | - let bar = 'baz'
2 | .foo(
3 | className = bar
4 | )
5 | .pure-u-1-3
6 |
--------------------------------------------------------------------------------
/test/fixtures/code.reiny:
--------------------------------------------------------------------------------
1 | ---
2 | let x = 1;
3 | let y = 2;
4 | let z = 3;
5 | ---
6 | - var aaa = 4;
7 | div
8 | - var beta = 5;
9 |
--------------------------------------------------------------------------------
/test/fixtures/comment.reiny:
--------------------------------------------------------------------------------
1 | // a
2 | div //b
3 | /* */
4 | span //b
5 | /*
6 | */
7 | span /* */ aaa
8 | // c
9 | // d
10 |
--------------------------------------------------------------------------------
/test/fixtures/custom-element.reiny:
--------------------------------------------------------------------------------
1 | ---
2 | let Foo = React.createClass({
3 | render: () => {
4 | return React.createElement('div', {className: 'foo'});
5 | }
6 | })
7 | ---
8 | // CamelCase becomes element reference
9 | Foo()
10 |
--------------------------------------------------------------------------------
/test/fixtures/direct-element.reiny:
--------------------------------------------------------------------------------
1 | - var el = React.createElement('div');
2 | +(el)
3 |
--------------------------------------------------------------------------------
/test/fixtures/embeded-code.reiny:
--------------------------------------------------------------------------------
1 | foo(
2 | a = {1}
3 | onClick = {- function(){console.log('foo')} -}
4 | )
5 |
6 | span = { a }
7 |
--------------------------------------------------------------------------------
/test/fixtures/entity-ref.reiny:
--------------------------------------------------------------------------------
1 | .foo
2 | | hogefuga
3 | = " "
4 | - let v = " "
5 | = v
6 |
--------------------------------------------------------------------------------
/test/fixtures/example.reiny:
--------------------------------------------------------------------------------
1 | - let items = [1, 2, 3];
2 |
3 | ---
4 | let Foo = React.createClass({
5 | render: () => {
6 | return React.createElement('div', {className: 'foo'});
7 | }
8 | })
9 | ---
10 |
11 | .container {
12 | background-color: #eee
13 | width: 640
14 | height: 480px
15 | }
16 | h1 This is an reiny example
17 |
18 | // CamelCase becomes reference
19 | Foo()
20 |
21 | // unicode
22 | span(
23 | key="--🐑--"
24 | )
25 |
26 | // ref with &
27 | span&foo()
28 |
29 | // for syntax
30 | ul
31 | for i in @items
32 | li(key=i) = i
33 |
34 | // if syntax
35 | if false
36 | a hoge fuga aaa
37 |
38 | // inline expression
39 | if { 2 > 1 }
40 | a(key='fooo') hoge fuga aaa
41 |
42 | // text
43 | | aaaa bbbb
44 |
45 | // object mixin as property
46 | - let o = {'data-a': 'aaa', 'data-b': 'bbb'};
47 | foo(
48 | > o
49 | onClick = {- function(){console.log('foo')} -}
50 | )
51 |
--------------------------------------------------------------------------------
/test/fixtures/for.reiny:
--------------------------------------------------------------------------------
1 | for i in items
2 | - console.log(i)
3 | span=i
4 |
5 | for i, n in @items
6 | li
7 |
--------------------------------------------------------------------------------
/test/fixtures/header.reiny:
--------------------------------------------------------------------------------
1 | h1 aaa
2 |
--------------------------------------------------------------------------------
/test/fixtures/identifier.reiny:
--------------------------------------------------------------------------------
1 | if @x
2 | foo
3 |
--------------------------------------------------------------------------------
/test/fixtures/if.reiny:
--------------------------------------------------------------------------------
1 | if true
2 | a
3 | else if false
4 | b
5 | c
6 | else
7 | c
8 |
--------------------------------------------------------------------------------
/test/fixtures/indent.reiny:
--------------------------------------------------------------------------------
1 | a
2 | a
3 | a
4 | a
5 | a
6 |
--------------------------------------------------------------------------------
/test/fixtures/inline-expr.reiny:
--------------------------------------------------------------------------------
1 | span = { 'text' }
2 | span.span(
3 | foo = { 'text3' }
4 | )
5 | span = {- function(){return 'text 2'} -}
6 |
--------------------------------------------------------------------------------
/test/fixtures/mergeable-object.reiny:
--------------------------------------------------------------------------------
1 | - let o = {'data-a': 'aaa', 'data-b': 'bbb'};
2 | - let p = {'data-c': 3, 'data-id': 4};
3 | foo(
4 | > o
5 | > p
6 | onClick = {- function(){console.log('foo')} -}
7 | )
8 |
--------------------------------------------------------------------------------
/test/fixtures/modifiers.reiny:
--------------------------------------------------------------------------------
1 | foo.a-b_c#uniq&someRef(className = aa){} a
2 |
--------------------------------------------------------------------------------
/test/fixtures/nested-style.reiny:
--------------------------------------------------------------------------------
1 | .foo {
2 | color: 'green'
3 | }
4 | if true
5 | if true
6 | .quux {
7 | color: #eee
8 | }
9 | else if { false }
10 | span() {
11 | color: @foo
12 | }
13 | else
14 | .bbb {
15 | color: bar
16 | }
17 | .bar {
18 | color: 'red'
19 | }
20 | .baz {
21 | color: 'blue'
22 | }
23 | if false
24 | .fuba {
25 | color: value
26 | }
27 |
--------------------------------------------------------------------------------
/test/fixtures/no-indent-element.reiny:
--------------------------------------------------------------------------------
1 | i.fa.fa-check
2 | |
3 | span = { __('Synced') }
4 | = { __('Synced') }
5 |
--------------------------------------------------------------------------------
/test/fixtures/prop-types.reiny:
--------------------------------------------------------------------------------
1 | @foo: string
2 | @bar: string?
3 | @items: string[]
4 | @numbers: number[]?
5 |
6 | .foo(
7 | id = @foo
8 | )
9 |
--------------------------------------------------------------------------------
/test/fixtures/style.reiny:
--------------------------------------------------------------------------------
1 | .container {
2 | background-color: #eee
3 | color: #AAA
4 | width: 640
5 | height: 480px
6 | }
7 | h1 hello
8 |
--------------------------------------------------------------------------------
/test/fixtures/text.reiny:
--------------------------------------------------------------------------------
1 | a='foo'
2 | a = @foo
3 | a aaa
4 |
5 | h1() foo bar baz
6 |
7 | Foo
8 |
--------------------------------------------------------------------------------
/test/preprocess-test.coffee:
--------------------------------------------------------------------------------
1 | {ok, equal} = require 'assert'
2 |
3 | preprocess = require '../src/preprocess'
4 |
5 | code = '''
6 | // a
7 | b
8 | /* aaa */
9 |
10 | /*
11 | bbb
12 | */
13 | '''
14 |
15 | console.log preprocess code
16 |
--------------------------------------------------------------------------------
/test/style-compiler-test.coffee:
--------------------------------------------------------------------------------
1 | fs = require 'fs'
2 | path = require 'path'
3 | reiny = require('../src/index')
4 | {inspect} = require('util')
5 | esprima = require('esprima')
6 |
7 | # Try to parse
8 | list = [
9 | 'classname'
10 | 'code'
11 | 'comment'
12 | 'custom-element'
13 | 'direct-element'
14 | 'embeded-code'
15 | 'example'
16 | 'for'
17 | 'if'
18 | 'header'
19 | 'identifier'
20 | 'prop-types'
21 | # 'inline-expr'
22 | 'indent'
23 | 'modifiers'
24 | 'style'
25 | 'mergeable-object'
26 | 'text'
27 | ]
28 |
29 | if target = process.argv[3] ? process.argv[2]
30 | styleCompile = require '../src/style-compiler'
31 |
32 | # exec
33 | console.error 'exec', target
34 |
35 | source = fs.readFileSync(path.join process.cwd(), target).toString()
36 | ast = reiny.parse(source)
37 | console.error inspect ast, depth: null # show ast
38 | code = styleCompile(ast) # show code
39 | console.log code
40 | # execTemp()
41 |
--------------------------------------------------------------------------------
/test/test.coffee:
--------------------------------------------------------------------------------
1 | fs = require 'fs'
2 | path = require 'path'
3 | reiny = require('../src/index')
4 | {inspect} = require('util')
5 |
6 | # Try to parse
7 | list = [
8 | 'classname'
9 | 'code'
10 | 'comment'
11 | 'custom-element'
12 | 'direct-element'
13 | 'embeded-code'
14 | 'example'
15 | 'for'
16 | 'header'
17 | 'identifier'
18 | 'prop-types'
19 | # 'inline-expr'
20 | 'indent'
21 | 'modifiers'
22 | 'style'
23 | 'mergeable-object'
24 | 'text'
25 | ]
26 |
27 | for i in list
28 | source = fs.readFileSync(path.join __dirname, "fixtures/#{i}.reiny").toString()
29 | try
30 | ast = reiny.parse(source)
31 | try
32 | compiled = reiny._compile ast
33 | Function compiled
34 | catch e
35 | console.error i + ' invalid output'
36 | console.error e
37 | process.exit(1)
38 |
39 | catch e
40 | console.error e
41 | throw i + ' parse failed'
42 |
43 | # exec
44 | execTemp = (code) ->
45 | global.React = require('react')
46 | eval(code
47 | .replace("module.exports", "global.__tmp")
48 | .replace("require('reiny/runtime')", "require('../src/runtime')")
49 | )
50 | c = React.createClass
51 | propTypes: __tmp.propTypes ? {}
52 | render: -> __tmp()
53 | console.error React.renderToStaticMarkup React.createElement(c, {})
54 |
55 | if target = process.argv[3] ? process.argv[2]
56 | console.error 'exec', target
57 |
58 | source = fs.readFileSync(path.join process.cwd(), target).toString()
59 | ast = null
60 | try
61 | ast = reiny.parse(source)
62 | catch e
63 | formatter = require('../src/format-error.coffee')
64 | throw new Error (formatter source, e)
65 |
66 | console.error inspect ast, depth: null # show ast
67 | code = reiny._compile(ast)
68 | console.log code # show code
69 | # execTemp(code)
70 |
--------------------------------------------------------------------------------