├── .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 | --------------------------------------------------------------------------------