├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── bin ├── taiji └── taiji.js ├── bootstrap ├── bin │ └── taiji.tj ├── lib │ ├── browser.tj │ ├── builtins │ │ ├── core.tj │ │ └── js.tj │ ├── command.tj │ ├── compiler │ │ ├── analyze.tj │ │ ├── compile.tj │ │ ├── env.tj │ │ ├── optimize.tj │ │ ├── package.tj │ │ ├── textize.tj │ │ └── transform.tj │ ├── module.tj │ ├── optparse.tj │ ├── package.tj │ ├── parser │ │ ├── base.tj │ │ ├── operator.tj │ │ ├── package.json │ │ └── parser.tj │ ├── register.tj │ ├── repl.tj │ ├── sourcemap.tj │ ├── taiji.tj │ └── utils.tj └── test │ ├── compiler │ ├── testcompileexpression.tj │ ├── testcompiler.tj │ ├── testcompilerbasic.tj │ ├── testcompilerdynamicgrammar.tj │ └── testoperator.tj │ ├── parser │ ├── testdynamicgrammar.tj │ ├── testoperator.tj │ ├── testparser.tj │ └── testparserbasic.tj │ ├── testcommand.tj │ ├── testeval.tj │ ├── testmodule.tj │ ├── testprotoconstructor.js │ ├── testshell.tj │ └── testutils.tj ├── doc ├── JavaScript.g ├── en │ ├── informal document status declaration.md │ ├── introduction.md │ └── the zen of taiji.md └── zh-cn │ ├── 太极语言规范.md │ └── 非正式文档状态声明.md ├── gulpfile.coffee ├── gulpfile.js ├── history.md ├── lib ├── browser.js ├── builtins │ ├── core.js │ └── js.js ├── command.js ├── compiler │ ├── analyze.js │ ├── compile.js │ ├── env.js │ ├── optimize.js │ ├── package.json │ ├── textize.js │ └── transform.js ├── module.js ├── optparse.js ├── package.json ├── parser │ ├── base.js │ ├── operator.js │ ├── package.json │ └── parser.js ├── register.js ├── repl.js ├── sourcemap.js ├── taiji.js └── utils.js ├── package.json ├── register.js ├── repl.js ├── roadmap.md ├── samples ├── block.tj ├── blockcomment.tj ├── bootstrap │ ├── readme.md │ ├── repl.tj │ ├── require.tj │ └── taijilang.tj ├── breakout │ ├── breakout.css │ ├── breakout.tj │ ├── index.html │ └── reamd.md ├── chatserver.tj ├── demo.tj ├── democlass.tj ├── ellipsis.tj ├── express_bootstrap.tj ├── hello.tj ├── import.tj ├── include.tj ├── indent-then-else.tj ├── let.tj ├── loop.tj ├── macros.tj ├── meta.tj ├── module1.tj ├── nodeserver.tj ├── sample.tj ├── sample2.tj ├── sequence.tj ├── snippets.tj ├── square-macro.tj └── twitter.tj ├── src ├── bin │ └── taiji.coffee ├── browser.coffee ├── builtins │ ├── core.coffee │ └── js.coffee ├── command.coffee ├── compiler │ ├── analyze.coffee │ ├── compile.coffee │ ├── env.coffee │ ├── optimize.coffee │ ├── package.json │ ├── textize.coffee │ └── transform.coffee ├── module.coffee ├── optparse.coffee ├── package.json ├── parser │ ├── base.coffee │ ├── operator.coffee │ ├── package.json │ └── parser.coffee ├── register.coffee ├── repl.coffee ├── sourcemap.coffee ├── taiji.coffee └── utils.coffee ├── taiji-libraries ├── browser.tj ├── class@.tj ├── html.tj ├── macros.tj ├── prelude.tj ├── types.tj ├── types@.tj └── utilities.tj ├── test-build ├── compiler │ ├── testcompileexpression.js │ ├── testcompiler.js │ ├── testcompilerbasic.js │ ├── testcompilerdynamicgrammar.js │ └── testoperator.js ├── parser │ ├── testdynamicgrammar.js │ ├── testoperator.js │ ├── testparser.js │ └── testparserbasic.js ├── testcommand.js ├── testeval.js ├── testmodule.js ├── testshell.js └── testutils.js ├── test ├── compiler │ ├── testcompileexpression.coffee │ ├── testcompiler.coffee │ ├── testcompilerbasic.coffee │ ├── testcompilerdynamicgrammar.coffee │ └── testoperator.coffee ├── parser │ ├── testdynamicgrammar.coffee │ ├── testoperator.coffee │ ├── testparser.coffee │ └── testparserbasic.coffee ├── testcommand.coffee ├── testeval.coffee ├── testmodule.coffee ├── testprotoconstructor.js ├── testshell.coffee └── testutils.coffee └── todo.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.html 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.swp 9 | *.swo 10 | .coverage_data 11 | cover_html 12 | 13 | .DS_Store 14 | lib-cov 15 | benchmarks 16 | node_modules 17 | dist 18 | .idea 19 | tmp 20 | temp 21 | temp.* 22 | dev 23 | build 24 | deprecated 25 | samples-js 26 | bootstrap-js 27 | 28 | /lib/compiler/metacompiled.js 29 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # files 2 | coverage.html 3 | .gitmodules 4 | .travis.yml 5 | History.md 6 | .gitattributes 7 | .gitignore 8 | 9 | # folders 10 | .git 11 | .idea 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 0.10 5 | - 0.11 6 | 7 | before_install: 8 | - npm install -g gulp 9 | 10 | script: 11 | - gulp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 曹星明(Caoxingming, simeon.chaos@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Taijilang 2 | Taijilang is a new powerful general programming language. Taijilang have more extensibility and customizability than all other existing programming languages. 3 | 4 | In general, the features of Taijilang can be summed up: more useful macro than in lisp, more important white space than in python, more general preprocess than in C, more powerful meta compilation than in metalua, more flexible dialect than in rebol, more optimized object code than in coffee-script. 5 | 6 | ### Features 7 | * Compiled to javascript language 8 | * Meta language, and lisp style macro is implemented as a special case of meta language 9 | * Flexible friendly syntax with attaching great importance to indent and white spaces, 10 | * The most customizable and extensible language, with the help of dynamic parser, macro and meta language features 11 | * Everything are expressions 12 | * Module and package 13 | * Optimized object code 14 | 15 | ### Project Address: 16 | [github: github.com/taijiweb/taijilang](https://www.github.com/taijiweb/taijilang) 17 | 18 | [npm: npmjs.org/package/taiji](https://www.npmjs.org/package/taiji) 19 | 20 | [google groups: taijilang](https://groups.google.com/forum/#!forum/taijilang) 21 | 22 | [G+: taiji lang](https://plus.google.com/u/0/114446069949044102399/posts/p/pub) 23 | 24 | QQ群: 太极语言 194928684 25 | 26 | ### Creator 27 | The creator of taijilang is [曹星明( Caoxingming, assumed name 太极真人(Taiji Zhenren) ) taijiweeb@gmail.com](taijiweeb@gmail.com). 28 | 29 | ### Thanks 30 | Thanks to the people who make the great things, I learned so much from them: 31 | 32 | [John McCarthy](http://www-formal.stanford.edu/jmc/), he invented the great language - [Lisp](http://en.wikipedia.org/wiki/Lisp), Taijilang follows the spirit of lisp in the heart. 33 | 34 | [Jeremy Ashkenas](http://ashkenas.com/), he [created coffee-script](https://github.com/jashkenas/coffeescript). I used [coffee-script](http://coffeescript.org/) to write Tajilang and learned a lot from it on how to create an elegant language and compile it to javascript. 35 | 36 | [Ryan Dahl](http://www.youtube.com/watch?v=ztspvPYybIY), he created [node.js](http://nodejs.org/), Taijilang runs on node.js. 37 | 38 | [Santosh Rajan](http://santoshrajan.com/), he created [lispyscript](github.com/santoshrajan/lispyscript), from which I got the instant spark to creating Taijilang. 39 | 40 | [TJ Holowaychuk](http://tjholowaychuk.com/), he shines the two letter "TJ" because of [so many great stuffs he have made](https://github.com/visionmedia), and I am honored to use .tj as the extension name of taijilang code file. 41 | 42 | I need thank to many other people and the stuffs made by them, too, although I can not list everyone of them here. 43 | 44 | At last, I'll thank to my family. 45 | 46 | **Let it go, let's start the game of throne, write a song of ice and fire in the taiji language.** 47 | -------------------------------------------------------------------------------- /bin/taiji: -------------------------------------------------------------------------------- 1 | var fs, lib, path; 2 | 3 | path = require('path'); 4 | 5 | fs = require('fs'); 6 | 7 | lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); 8 | 9 | require(lib + '/command').run(); 10 | -------------------------------------------------------------------------------- /bin/taiji.js: -------------------------------------------------------------------------------- 1 | var fs, lib, path; 2 | 3 | path = require('path'); 4 | 5 | fs = require('fs'); 6 | 7 | lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); 8 | 9 | require(lib + '/command').run(); 10 | -------------------------------------------------------------------------------- /bootstrap/bin/taiji.tj: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | taiji language 0.1 3 | 4 | path = require('path') 5 | fs = require('fs') 6 | 7 | lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib') 8 | require(lib + '/command').run() -------------------------------------------------------------------------------- /bootstrap/lib/browser.tj: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/browser.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | this file is not tested in taiji still. 6 | ### 7 | ### 8 | Copyright (c) 2009-2014 Jeremy Ashkenas 9 | Copyright (c) 2014-2015 Caoxingming 10 | 11 | Permission is hereby granted, free of charge, to any person 12 | obtaining a copy of this software and associated documentation 13 | files (the "Software"), to deal in the Software without 14 | restriction, including without limitation the rights to use, 15 | copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the 17 | Software is furnished to do so, subject to the following 18 | conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 25 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 27 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 28 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 | OTHER DEALINGS IN THE SOFTWARE. 31 | ### 32 | 33 | # This **Browser** compatibility layer extends core taiji functions 34 | # to make things work smoothly when compiling code directly in the browser. 35 | # We add support for loading remote Coffee scripts via **XHR**, and 36 | # `text/taiji` script tags, source maps via data-URLs, and so on. 37 | 38 | taiji = require './taiji' 39 | taiji.require = require 40 | compile = taiji.compile 41 | 42 | # Use standard JavaScript `eval` to eval code. 43 | taiji.eval = (code, options = {}) -> 44 | options.bare ?= true 45 | eval compile code, options 46 | 47 | # Running code does not provide access to this scope. 48 | taiji.run = (code, options = {}) -> 49 | options.bare = true 50 | options.shiftLine = true 51 | Function(compile code, options)() 52 | 53 | # If we're not in a browser environment, we're finished with the public API. 54 | return unless window? 55 | 56 | # Include source maps where possible. If we've got a base64 encoder, a 57 | # JSON serializer, and tools for escaping unicode characters, we're good to go. 58 | # Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa 59 | if btoa? and JSON? and unescape? and encodeURIComponent? 60 | compile = (code, options = {}) -> 61 | options.sourceMap = true 62 | options.inline = true 63 | {js, v3SourceMap} = taiji.compile code, options 64 | "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=taiji" 65 | 66 | # Load a remote script from the current domain via XHR. 67 | taiji.load = (url, callback, options = {}, hold = false) -> 68 | options.sourceFiles = [url] 69 | xhr = if window.ActiveXObject 70 | new window.ActiveXObject('Microsoft.XMLHTTP') 71 | else 72 | new window.XMLHttpRequest() 73 | xhr.open 'GET', url, true 74 | xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr 75 | xhr.onreadystatechange = -> 76 | if xhr.readyState is 4 77 | if xhr.status in [0, 200] 78 | param = [xhr.responseText, options] 79 | taiji.run param... unless hold 80 | else 81 | throw new Error "Could not load #{url}" 82 | callback param if callback 83 | xhr.send null 84 | 85 | # Activate taiji in the browser by having it compile and evaluate all script tags with a content-type of `text/taiji`. 86 | # This happens on page load. 87 | runScripts = -> 88 | scripts = window.document.getElementsByTagName 'script' 89 | taijitypes = ['text/taiji'] 90 | taijis = (s for s in scripts when s.type in taijitypes) 91 | index = 0 92 | 93 | execute = -> 94 | param = taijis[index] 95 | if param instanceof Array 96 | taiji.run param... 97 | index++ 98 | execute() 99 | 100 | for script, i in taijis 101 | do (script, i) -> 102 | options = literate: script.type is taijitypes[1] 103 | if script.src then taiji.load script.src,((param) -> taijis[i] = param; execute()), options, true 104 | else 105 | options.sourceFiles = ['embedded'] 106 | taijis[i] = [script.innerHTML, options] 107 | 108 | execute() 109 | 110 | # Listen for window load, both in decent browsers and in IE. 111 | if window.addEventListener then window.addEventListener 'DOMContentLoaded', runScripts, no 112 | else window.attachEvent 'onload', runScripts 113 | -------------------------------------------------------------------------------- /bootstrap/lib/compiler/analyze.tj: -------------------------------------------------------------------------------- 1 | {str, entity, isValue, isArray, extend, error, wrapInfo1} = require '../utils' 2 | 3 | truth = (exp, env) -> 4 | exp = entity(exp) 5 | if not exp? then return 2-!!exp 6 | if typeof exp == 'string' 7 | if exp[0]=='"' then return 2-!!exp[1...exp.length-1] 8 | else return 9 | else if exp.push then return 10 | return 2-!!exp 11 | 12 | setValue = (x) -> 13 | if x==undefined then undefinedExp 14 | else if typeof x == 'string' then '"'+x+'"' 15 | else x 16 | 17 | #todo: maybe this utility can be deprecated, because we can eval(tocode(exp)) 18 | getValue = (x) -> entity(x) 19 | 20 | analyzeDefinition = (exp, env) -> 21 | 22 | analyzeFnMap = 23 | '=': (exp, env) -> 24 | left = exp[1] 25 | eLeft = entity(left) 26 | if typeof eLeft=='string' 27 | # while optimizing, replace the reference of left with value unconditionally. 28 | # is this necessary to do this while analyzing? 29 | if left.const and isAtomicValue(exp[2]) then exp.removable = true 30 | else 31 | info = env.info(left) 32 | if not info then env.optimizeInfoMap[left] = info = {} 33 | info.assign = exp 34 | exp.refCount = 0 35 | else analyze(left, env); analyze(exp[2], env) 36 | 37 | 'var': (exp, env) -> 38 | v = entity(exp[1]) 39 | env.optimizeInfoMap[v] = info = {} 40 | info.assign = undefined 41 | info.decl = exp 42 | 43 | # because now is after transforming, so prefix! is only object language prefix operator. 44 | 'prefix!': (exp, env) -> analyze(exp[2], env) 45 | 'suffix!': (exp, env) -> analyze(exp[2], env) 46 | 'binary!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 47 | 'augmentAssign!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 48 | 'attribute!': (exp, env) -> analyze(exp[1], env) 49 | 'index!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 50 | 'augmentAssign!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 51 | 'list!': (exp, env) -> for e in exp[1...] then analyze(e, env) 52 | 'begin!': (exp, env) -> for e in exp[1...] then analyze(e, env) 53 | 54 | 'debugger': (exp, env) -> 55 | 'break': (exp, env) -> 56 | 'continue': (exp, env) -> 57 | 'return': (exp, env) -> analyze(exp[1], env) 58 | 'quote!': (exp, env) -> 59 | 'regexp!': (exp, env) -> 60 | 'noop!': (exp, env) -> 61 | 'jsvar!': (exp, env) -> # analyze(exp[1], env) # do not change reference count for jsvar! 62 | 'label!': (exp, env) -> analyze(exp[1], env) 63 | 'new': (exp, env) -> analyze(exp[1], env) 64 | 'hash!': (exp, env) -> analyze(exp[1], env) 65 | 'hashitem!': (exp, env) -> analyze(exp[2], env) 66 | 'call!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 67 | 68 | 'if': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env); analyze(exp[3], env) 69 | 'while': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 70 | 'doWhile!': (exp, env) -> analyze(exp[2], env); analyze(exp[1], env) 71 | 'forIn!': (exp, env) -> 72 | # [forIn! loopVariable range body] 73 | # loopVariable should not be treated as variable reference, so exp[1] is skipped 74 | analyze(exp[2], env); analyze(exp[3], env) 75 | 'cFor!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env); analyze(exp[3], env); analyze(exp[4], env) 76 | 'try!': (exp, env) -> 77 | # [try test catchVariable catchBody finallyBody] 78 | # catchVariable should not be treated as catchVariable reference, so exp[2] is skipped 79 | analyze(exp[1], env); analyze(exp[3], env); analyze(exp[4], env) 80 | 'switch!': (exp, env) -> 81 | # [switch test cases body] 82 | analyze(exp[1], env); analyze(exp[1], env); analyze(exp[1], env) 83 | 84 | # ->, =>, |->, |=> have been transformed to function! 85 | #[function! [params...] body] 86 | 'function': (exp, env) -> 87 | # use the env which is own to [function! ...] 88 | env = exp.env; env.optimizeInfoMap = {} 89 | for e in exp[1] then env.optimizeInfoMap[entity(e)] = info = {}; info.assign = [] 90 | analyze(exp[2], exp.env) 91 | 92 | 'letloop': (exp, env) -> 93 | #[params, bindings, body] 94 | env = exp.env; env.optimizeInfoMap = {} 95 | bindings = exp[2] 96 | for b in bindings then transform(b[1], env) 97 | analyze(exp[3], env) 98 | 99 | exports.analyze = analyze = (exp, env) -> 100 | e = entity exp 101 | if not e then return 102 | if typeof e == 'string' 103 | if e[0]=='"' then return 104 | info = env.info(e) 105 | if info and info.assign then info.assign.refCount++ 106 | if info and info.decl then info.decl.refCount++ 107 | if not exp.push then return 108 | if exp.analyzed then return 109 | if fn=analyzeFnMap[exp[0]] 110 | result = fn(exp, env) 111 | if result==exp then return result 112 | if result and result.push then result.analyzed = true 113 | result = wrapInfo1 result, exp 114 | result.env = env 115 | else 116 | for e in exp then analyze(e, env) 117 | exp.analyzed = true -------------------------------------------------------------------------------- /bootstrap/lib/compiler/env.tj: -------------------------------------------------------------------------------- 1 | {extend, javascriptKeywordSet, entity} = require '../utils' 2 | {identifierCharSet} = require '../parser/base' 3 | 4 | hasOwnProperty = Object::hasOwnProperty 5 | 6 | toIdentifier = (symbol) -> 7 | result = '' 8 | for c in symbol 9 | if identifierCharSet[c] then result += c 10 | else result += '$' 11 | if javascriptKeywordSet[symbol] then result += '1' 12 | result 13 | 14 | error = (msg, exp) -> 15 | if exp then throw Error msg+': '+exp 16 | else throw Error msg 17 | 18 | class SymbolLookupError extends Error 19 | constructor: (@msg, @exp) -> 20 | 21 | # options: {module, functionInfo, parser, ...} 22 | exports.Environment = class Environment 23 | constructor: (@scope, @parent, @parser, @module, @functionInfo, @options) -> 24 | if functionInfo 25 | functionInfo['backFillBlock!'] = [] 26 | @localScopeLevel = 0 27 | else @localScopeLevel = parent.localScopeLevel+1 28 | if parent then @meta = parent.meta 29 | else @meta = {list: [], code: [], index:0, env: @extend({})} 30 | 31 | extend: (scope, parser, module, functionInfo, options) -> 32 | new Environment(scope or @scope, @, parser or @parser, module or @module, functionInfo, options or @options) 33 | 34 | getFunctionInfo: -> 35 | env = @ 36 | while not functionInfo = env.functionInfo then env = env.parent 37 | functionInfo 38 | 39 | getFunctionEnv: -> 40 | env = @ 41 | while not env.functionInfo then env = env.parent 42 | env 43 | 44 | newVar: (symbol) -> 45 | name = toIdentifier(symbol) 46 | functionInfo = @getFunctionInfo() 47 | if not hasOwnProperty.call(functionInfo, name) 48 | functionInfo[name] = 1; {symbol: name} 49 | else 50 | while symbolIndex = name+(++functionInfo[name]) 51 | if not hasOwnProperty.call(functionInfo, symbolIndex) then break 52 | functionInfo[symbolIndex] = 1 53 | {symbol: symbolIndex} 54 | 55 | constVar: (symbol) -> v = @newVar(symbol); v.const = true; v 56 | ssaVar: (symbol) -> v = @newVar(symbol); v.ssa = true; v 57 | 58 | #__taiji$AnyIdentifier__ -> __taiji$AnyIdentifier???__, where ??? is index to avoid conflicting 59 | newTaijiVar: (symbol) -> 60 | name = toIdentifier(symbol) 61 | functionInfo = @getFunctionInfo() 62 | if not hasOwnProperty.call(functionInfo, name) 63 | functionInfo[name] = 1; {symbol: name} 64 | else 65 | while symbolIndex = name[...name.length-2]+(++functionInfo[name])+name[name.length-2...] 66 | if not hasOwnProperty.call(functionInfo, symbolIndex) then break 67 | functionInfo[symbolIndex] = 1 68 | {symbol: symbolIndex} 69 | 70 | getSymbolIndex: (symbol) -> 71 | functionInfo = @getFunctionInfo() 72 | if not hasOwnProperty.call(functionInfo, symbol) then return 0 73 | else return functionInfo[symbol] 74 | 75 | hasLocal: (symbol) -> hasOwnProperty.call(@scope, symbol) 76 | 77 | hasFnLocal: (symbol) -> 78 | if hasOwnProperty.call(@scope, symbol) then return true 79 | if @functionInfo then return 80 | else if @parent then return @parent.hasFnLocal(symbol) 81 | 82 | # all variables name relating to symbol 83 | fnLocalNames: (symbol) -> 84 | names = {} 85 | env = @ 86 | while 1 87 | if env.scope and hasOwnProperty.call(env.scope, symbol) 88 | names[env.scope[symbol].symbol] = 1 89 | if env.functionInfo then return names 90 | else if env.parent then env = env.parent 91 | else return names 92 | 93 | # use @@x to get variable x in outer var scope( outer function or module variable) 94 | outerVarScopeEnv: -> 95 | parent = @ 96 | while 1 97 | if parent.functionInfo 98 | if parent.parent then return parent.parent 99 | else return @ # instead of returning parent, return @. because the check in core.coffee exports['='] if env!=outerEnv and env.get(name) 100 | else parent = parent.parent 101 | 102 | set: (symbol, value) -> 103 | functionInfo = @getFunctionInfo() 104 | if typeof(value) == 'object' then value.value = name = toIdentifier(entity(value)) 105 | else value = name = toIdentifier(value) 106 | if not functionInfo[name] then functionInfo[name] = 1 107 | eValue = entity(value) 108 | if not functionInfo[eValue] then functionInfo[eValue] = 1 109 | @scope[symbol] = value 110 | 111 | get: (symbol) -> 112 | if hasOwnProperty.call(@scope, symbol) then return @scope[symbol] 113 | else if @parent then return @parent.get(symbol) 114 | 115 | info: (symbol) -> 116 | if @optimizeInfoMap and hasOwnProperty.call(@optimizeInfoMap, symbol) then return @optimizeInfoMap[symbol] 117 | else if @parent then return @parent.info(symbol) 118 | 119 | # analysis and optimization use the same environment, but add the property "optimizeInfoMap" to the env instance 120 | # the root env is the initial env which is be used to convert and transform the exp 121 | # when 'function!' is met, the corresponding env is used. -------------------------------------------------------------------------------- /bootstrap/lib/compiler/package.tj: -------------------------------------------------------------------------------- 1 | {"main":"compile.js"} -------------------------------------------------------------------------------- /bootstrap/lib/module.tj: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | path = require 'path' 3 | 4 | # If obj.hasOwnProperty has been overridden, then calling obj.hasOwnProperty(prop) will break. 5 | # See: https:# github.com/joyent/node/issues/1707 6 | hasOwnProperty = (obj, prop) -> Object.prototype.hasOwnProperty.call(obj, prop) 7 | 8 | modulePaths = [] 9 | 10 | module.exports = exports = TaijiModule = (filePath, @parent) -> 11 | @exports = {} # meta exports for the module 12 | if not filePath 13 | if @parent then @filePath = @parent.filePath 14 | else @filePath = __filename 15 | else if not @parent then @filePath = filePath 16 | else @filePath = @parent.findPath(filePath) 17 | @basePath = path.dirname(@filePath) 18 | if @parent 19 | @modulePaths = @parent.modulePaths.slice() 20 | @modulePaths.unshift path.resolve(@basePath, '../taiji-libraries') 21 | else 22 | @modulePaths = modulePaths.slice() 23 | @modulePaths.unshift path.resolve(@basePath, '../taiji_modules') 24 | return this 25 | 26 | TaijiModule._initPaths = -> 27 | if process.env['TAIJILANG_PATH'] 28 | splitter = if process.platform == 'win32' then ';' else ':' 29 | paths = process.env['TAIJILANG_PATH'].split(splitter) 30 | for path1, i in paths then paths[i] = path.resolve(path1, 'taiji-libraries') 31 | modulePaths = paths 32 | 33 | TaijiModule._initPaths() 34 | 35 | # In order to minimize unnecessary lstat() calls, this cache is a list of known-real paths. Set to an empty object to reset. 36 | _realpathCache = {} 37 | 38 | # check if the file exists and is not a directory 39 | tryFile = (requestPath) -> 40 | try 41 | stats = fs.statSync(requestPath) 42 | if stats && !stats.isDirectory() then fs.realpathSync(requestPath, _realpathCache) 43 | catch ex then return false 44 | 45 | tryPath = (filePath, trailingSlash) -> 46 | if !trailingSlash 47 | filename = tryFile(filePath) 48 | if !filename && filePath.slice(-3)!='.tj' 49 | filename = tryFile(filePath + '.tj') 50 | if !filename 51 | mainPath = path.resolve(filePath, 'main.tj') 52 | filename = tryFile(mainPath) 53 | filename 54 | 55 | TaijiModule.matchPaths = (request, paths) -> 56 | trailingSlash = request.slice(-1) == '/' 57 | for path1 in paths 58 | if filename = tryPath path.resolve(path1, request), trailingSlash then return filename 59 | 60 | TaijiModule::findPath = (filePath) -> 61 | if filePath=='**evaluated taijilang code**' then return filePath 62 | if fs.exists(filePath) then return filePath 63 | start = filePath.substring(0, 2) 64 | if start=='./' or start=='.\\' or start=='..' 65 | trailingSlash = filePath.slice(-1) == '/' 66 | filename = tryPath(path.resolve(@basePath, filePath), trailingSlash) 67 | else 68 | if filePath.charAt(0) == '/' then paths = [''] # absolute path, no other paths is searched 69 | else paths = @modulePaths 70 | filename = TaijiModule.matchPaths(filePath, paths) 71 | if !filename 72 | err = new Error("Cannot find module '" + filePath + "'") 73 | err.code = 'MODULE_NOT_FOUND' 74 | throw err 75 | return filename -------------------------------------------------------------------------------- /bootstrap/lib/optparse.tj: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/optparse.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | ### 6 | ### 7 | Copyright (c) 2009-2014 Jeremy Ashkenas 8 | Copyright (c) 2014-2015 Caoxingming 9 | 10 | Permission is hereby granted, free of charge, to any person 11 | obtaining a copy of this software and associated documentation 12 | files (the "Software"), to deal in the Software without 13 | restriction, including without limitation the rights to use, 14 | copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the 16 | Software is furnished to do so, subject to the following 17 | conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | ### 31 | 32 | # A simple **OptionParser** class to parse option flags from the command-line. 33 | # Use it like so: 34 | # parser = new OptionParser switches, helpBanner 35 | # options = parser.parse process.argv 36 | # The first non-option is considered to be the start of the file (and file 37 | # option) list, and all subsequent arguments are left unparsed. 38 | exports.OptionParser = class OptionParser 39 | # Initialize with a list of valid options, in the form: 40 | # [short-flag, long-flag, description] 41 | # Along with an an optional banner for the usage help. 42 | constructor: (rules, @banner) -> 43 | @rules = buildRules rules 44 | 45 | # Parse the list of arguments, populating an `options` object with all of the 46 | # specified options, and return it. Options after the first non-option 47 | # argument are treated as arguments. `options.arguments` will be an array 48 | # containing the remaining arguments. This is a simpler API than many option 49 | # parsers that allow you to attach callback actions for every flag. Instead, 50 | # you're responsible for interpreting the options object. 51 | parse: (args) -> 52 | options = arguments: [] 53 | skippingArgument = no 54 | originalArgs = args 55 | args = normalizeArguments args 56 | for arg, i in args 57 | if skippingArgument 58 | skippingArgument = no 59 | continue 60 | if arg is '--' 61 | pos = originalArgs.indexOf '--' 62 | options.arguments = options.arguments.concat originalArgs[(pos + 1)..] 63 | break 64 | isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG)) 65 | # the CS option parser is a little odd; options after the first 66 | # non-option argument are treated as non-option arguments themselves 67 | seenNonOptionArg = options.arguments.length > 0 68 | unless seenNonOptionArg 69 | matchedRule = no 70 | for rule in @rules 71 | if rule.shortFlag is arg or rule.longFlag is arg 72 | value = true 73 | if rule.hasArgument 74 | skippingArgument = yes 75 | value = args[i + 1] 76 | options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value 77 | matchedRule = yes 78 | break 79 | throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule 80 | if seenNonOptionArg or not isOption 81 | options.arguments.push arg 82 | options 83 | 84 | # Return the help text for this **OptionParser**, listing and describing all 85 | # of the valid options, for `--help` and such. 86 | help: -> 87 | lines = [] 88 | lines.unshift "#{@banner}\n" if @banner 89 | for rule in @rules 90 | spaces = 15 - rule.longFlag.length 91 | spaces = if spaces > 0 then repeat ' ', spaces else '' 92 | letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' ' 93 | lines.push ' ' + letPart + rule.longFlag + spaces + rule.description 94 | "\n#{ lines.join('\n') }\n" 95 | 96 | # Regex matchers for option flags. 97 | LONG_FLAG = /^(--\w[\w\-]*)/ 98 | SHORT_FLAG = /^(-\w)$/ 99 | MULTI_FLAG = /^-(\w{2,})/ 100 | OPTIONAL = /\[(\w+(\*?))\]/ 101 | 102 | # Build and return the list of option rules. If the optional *short-flag* is 103 | # unspecified, leave it out by padding with `null`. 104 | buildRules = (rules) -> 105 | for tuple in rules 106 | tuple.unshift null if tuple.length < 3 107 | buildRule tuple... 108 | 109 | # Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the 110 | # description of what the option does. 111 | buildRule = (shortFlag, longFlag, description, options = {}) -> 112 | match = longFlag.match(OPTIONAL) 113 | longFlag = longFlag.match(LONG_FLAG)[1] 114 | { 115 | name: longFlag.substr 2 116 | shortFlag: shortFlag 117 | longFlag: longFlag 118 | description: description 119 | hasArgument: !!(match and match[1]) 120 | isList: !!(match and match[2]) 121 | } 122 | 123 | # Normalize arguments by expanding merged flags into multiple flags. This allows 124 | # you to have `-wl` be the same as `--watch --lint`. 125 | normalizeArguments = (args) -> 126 | args = args[..]; result = [] 127 | for arg in args 128 | if match = arg.match MULTI_FLAG then result.push '-' + l for l in match[1].split '' 129 | else result.push arg 130 | result 131 | 132 | # Repeat a string `n` times. 133 | repeat = (str, n) -> 134 | # Use clever algorithm to have O(log(n)) string concatenation operations. 135 | res = '' 136 | while n > 0 137 | res += str if n & 1 138 | n >>>= 1 139 | str += str 140 | res 141 | -------------------------------------------------------------------------------- /bootstrap/lib/package.tj: -------------------------------------------------------------------------------- 1 | {"main":"taiji.js"} -------------------------------------------------------------------------------- /bootstrap/lib/parser/base.tj: -------------------------------------------------------------------------------- 1 | utils = require '../utils' 2 | 3 | exports.entity = utils.entity 4 | exports.debug = utils.debug 5 | exports.warn = utils.warn 6 | exports.str = str = utils.str 7 | exports.convertIdentifier = utils.convertIdentifier 8 | exports.isArray = utils.isArray 9 | exports.extend = utils.extend 10 | exports.wrapInfo1 = utils.wrapInfo1 11 | exports.wrapInfo2 = utils.wrapInfo2 12 | exports.charset = charset = utils.charset 13 | 14 | exports.digits = digits = '0123456789' 15 | exports.lowers = lowers = 'abcdefghijklmnopqrstuvwxyz' 16 | exports.uppers = uppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 17 | exports.letters = letters = lowers+uppers 18 | exports.letterDigits = letterDigits = letters+digits 19 | exports.letterDigitSet = charset letterDigits 20 | exports.firstIdentifierChars = firstIdentifierChars = '$_'+letters 21 | exports.identifierChars = identifierChars = firstIdentifierChars+digits 22 | exports.taijiIdentifierChars = taijiIdentifierChars = '!?'+identifierChars 23 | exports.digitCharSet = digitCharSet = charset(exports.digits) 24 | exports.letterCharSet = letterCharSet = charset(exports.letters) 25 | exports.firstIdentifierCharSet = charset('$_'+letters) 26 | exports.identifierCharSet = identifierCharSet = charset(identifierChars) 27 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars) 28 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars) 29 | 30 | NUMBER=1; STRING=2; IDENTIFIER=3; SYMBOL=4; REGEXP=5; HEAD_SPACES=6; CONCAT_LINE=7; PUNCT=8; FUNCTION=9 31 | BRACKET=10; PAREN=11; DATA_BRACKET=12; CURVE=13; INDENT_EXPRESSION=14 32 | NEWLINE=15; SPACES=16; INLINE_COMMENT=17; SPACES_INLINE_COMMENT=18; LINE_COMMENT=19; BLOCK_COMMENT=20; CODE_BLOCK_COMMENT=21; CONCAT_LINE=22 33 | MODULE_HEADER=23; MODULE=24 34 | NON_INTERPOLATE_STRING=25; INTERPOLATE_STRING=26 35 | INDENT=27; UNDENT=28; HALF_DENT=29; EOI=30; C_BLOCK_COMMENT = 31; SPACE_COMMENT = 32; TAIL_COMMENT=33 36 | #PAREN_OPERATOR_EXPRESSION=33; COMPACT_CLAUSE_EXPRESSION=34; SPACE_CLAUSE_EXPRESSION=35 37 | 38 | exports.constant = {NUMBER, STRING, IDENTIFIER, SYMBOL, REGEXP, HEAD_SPACES, CONCAT_LINE, PUNCT, FUNCTION, 39 | BRACKET, PAREN, DATA_BRACKET, CURVE, INDENT_EXPRESSION 40 | NEWLINE, SPACES, INLINE_COMMENT, SPACES_INLINE_COMMENT, LINE_COMMENT, BLOCK_COMMENT, CODE_BLOCK_COMMENT, CONCAT_LINE 41 | MODULE_HEADER, MODULE 42 | NON_INTERPOLATE_STRING, INTERPOLATE_STRING 43 | INDENT, UNDENT, HALF_DENT, EOI, C_BLOCK_COMMENT, SPACE_COMMENT, TAIL_COMMENT 44 | #PAREN_OPERATOR_EXPRESSION, COMPACT_CLAUSE_EXPRESSION, SPACE_CLAUSE_EXPRESSION 45 | } -------------------------------------------------------------------------------- /bootstrap/lib/parser/package.json: -------------------------------------------------------------------------------- 1 | {"main":"parser.js"} -------------------------------------------------------------------------------- /bootstrap/lib/register.tj: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/register.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | ### 6 | ### 7 | Copyright (c) 2009-2014 Jeremy Ashkenas 8 | Copyright (c) 2014-2015 Caoxingming 9 | 10 | Permission is hereby granted, free of charge, to any person 11 | obtaining a copy of this software and associated documentation 12 | files (the "Software"), to deal in the Software without 13 | restriction, including without limitation the rights to use, 14 | copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the 16 | Software is furnished to do so, subject to the following 17 | conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | ### 31 | 32 | child_process = require 'child_process' 33 | path = require 'path' 34 | taiji = require './taiji' 35 | utils = require './utils' 36 | 37 | # Load and run a taiji file for Node, stripping any `BOM`s. 38 | loadFile = (module, filename) -> 39 | answer = taiji._compileFile filename, false 40 | module._compile answer, filename 41 | 42 | # If the installed version of Node supports `require.extensions`, register taiji as an extension. 43 | if require.extensions 44 | for ext in taiji.FILE_EXTENSIONS then require.extensions[ext] = loadFile 45 | 46 | # Patch Node's module loader to be able to handle multi-dot extensions. 47 | # This is a horrible thing that should not be required. 48 | Module = require 'module' 49 | 50 | findExtension = (filename) -> 51 | extensions = path.basename(filename).split '.' 52 | # Remove the initial dot from dotfiles. 53 | extensions.shift() if extensions[0] is '' 54 | # Start with the longest possible extension and work our way shortwards. 55 | while extensions.shift() 56 | curExtension = '.' + extensions.join '.' 57 | return curExtension if Module._extensions[curExtension] 58 | '.js' 59 | 60 | Module::load = (filename) -> 61 | @filename = filename 62 | @paths = Module._nodeModulePaths path.dirname filename 63 | extension = findExtension filename 64 | Module._extensions[extension](this, filename) 65 | @loaded = true 66 | 67 | # If we're on Node, patch `child_process.fork` so that taiji scripts are able to fork both taiji files, and JavaScript files, directly. 68 | if child_process 69 | {fork} = child_process 70 | binary = require.resolve '../bin/taiji' 71 | child_process.fork = (path, args, options) -> 72 | if utils.isTaiji path 73 | unless Array.isArray args then options = args or {}; args = [] 74 | args = [path].concat args 75 | path = binary 76 | fork path, args, options 77 | -------------------------------------------------------------------------------- /bootstrap/lib/taiji.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | // The current taiji version number. 4 | exports.VERSION = '0.1.0' 5 | 6 | {extend begin formatTaijiJson addPrelude} = require './utils' 7 | TaijiModule = require './module' 8 | {Parser} = require './parser' 9 | {entity} = require './parser/base' 10 | exports.Parser = Parser 11 | {Environment metaConvert transformExp optimizeExp compileExp metaCompile compileExpNoOptimize} = require './compiler' 12 | exports.Environment = Environment 13 | exports.compileExp = compileExp 14 | exports.builtins = extend {..} require('./builtins/core') require('./builtins/js') 15 | 16 | exports.textizerOptions = textizerOptions = {. 17 | indentWidth: 2; lineLength: 80 18 | .} 19 | 20 | exports.rootModule = rootModule = new TaijiModule(__filename, null) 21 | 22 | exports.initEnv = initEnv = (builtins, taijiModule, options) -> 23 | options = extend options textizerOptions 24 | // Environment(scope=builtins, parent=null, new Parser, taijiModule, newVarIndexMap={..}, options) 25 | env = new Environment(extend({}, builtins), null, new Parser, taijiModule, {..}, options) 26 | env.parser = new Parser 27 | env 28 | 29 | exports.parse = (code, taijiModule, builtins, options) -> 30 | env = initEnv(builtins, taijiModule, options); parser = env.parser 31 | exp = parser.parse(code, parser.module, 0, env) 32 | formatTaijiJson(entity(exp.body), 0, 0, false, 2, 70) 33 | 34 | exports.convert = (code, taijiModule, builtins, options) -> 35 | env = initEnv(builtins, taijiModule, options); parser = env.parser 36 | var exp = parser.parse(code, parser.module, 0, env) 37 | exp = metaConvert(addPrelude(parser, exp.body), env) 38 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 39 | 40 | exports.transform = (code, taijiModule, builtins, options) -> 41 | env = initEnv(builtins, taijiModule, options); parser = env.parser 42 | var exp = parser.parse(code, parser.module, 0, env) 43 | exp = transformExp(addPrelude(parser, exp.body), env) 44 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 45 | 46 | exports.optimize = (code, taijiModule, builtins, options) -> 47 | env = initEnv(builtins, taijiModule, options); parser = env.parser 48 | var exp = parser.parse(code, parser.module, 0, env) 49 | exp = optimizeExp(addPrelude(parser, exp.body), env) 50 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 51 | 52 | exports.compileInteractive = compileInteractive = (code, taijiModule, builtins, options) -> 53 | env = initEnv(builtins, taijiModule, options); parser = env.parser 54 | exp = parser.parse(code, parser.moduleBody, 0, env) 55 | objCode = compileExp(exp, env) 56 | 57 | exports.metaCompile = (code, taijiModule, builtins, options) -> 58 | env = initEnv(builtins, taijiModule, options); parser = env.parser 59 | exp = parser.parse(code, parser.module, 0, env) 60 | objCode = metaCompile(addPrelude(parser, exp.body), [], env) 61 | 62 | exports.compile = compile = (code, taijiModule, builtins, options) -> 63 | env = initEnv(builtins, taijiModule, options); parser = env.parser 64 | exp = parser.parse(code, parser.module, 0, env) 65 | objCode = compileExp(addPrelude(parser, exp.body), env) 66 | 67 | exports.compileNoOptimize = (code, taijiModule, builtins, options) -> 68 | env = initEnv(builtins, taijiModule, options); parser = env.parser 69 | exp = parser.parse(code, parser.module, 0, env) 70 | objCode = compileExpNoOptimize(addPrelude(parser, exp.body), env) 71 | 72 | exports.eval = (code, taijiModule, builtins, options) -> 73 | x = compile(code, taijiModule, builtins, options) 74 | eval x 75 | 76 | exports.FILE_EXTENSIONS = ['.taiji', '.tj'] 77 | 78 | exports.register = -> require './register' 79 | 80 | extern! Error 81 | 82 | // Throw error with deprecation warning when depending upon implicit `require.extensions` registration 83 | if require.extensions then 84 | for ext in exports.FILE_EXTENSIONS then 85 | if not require.extensions[ext] then require.extensions[ext] = -> 86 | throw new Error "Use taiji.register\() or require the taiji/register module to require {ext} files." -------------------------------------------------------------------------------- /bootstrap/test/compiler/testcompileexpression.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | nit = ndescribe = -> 6 | 7 | lib = '../../lib/' 8 | {Environment, textizerOptions, builtins, initEnv, rootModule} = require lib+'taiji' 9 | {compileExp, compileExpNoOptimize} = compiler = require lib+'compiler' 10 | {extend} = require lib+'utils' 11 | 12 | compile = (exp) -> compileExp(exp, initEnv(builtins, rootModule, {})) 13 | compileNoOptimize = (code) -> compileExpNoOptimize(exp, initEnv(builtins, rootModule, {})) 14 | 15 | transform = (exp) -> 16 | compiler.transform(exp, initEnv(builtins, rootModule, {})) 17 | 18 | describe "compile expression: ", -> 19 | describe "simple: ", -> 20 | it 'should compile 1', -> 21 | expect(compile(1)).to.equal '1' 22 | it '''should compile [',', ['=', 'x',1], []]]''', -> 23 | expect(compile(['binary,', ['=', 'x',1], []])).to.equal "var x = 1;\nx, [];" 24 | it '''should compile ['binary,', 1, []]''', -> 25 | expect(compile(['binary,', 1, []])).to.equal "1, []" 26 | -------------------------------------------------------------------------------- /bootstrap/test/compiler/testcompilerdynamicgrammar.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | nit = -> 6 | 7 | lib = '../../lib/' 8 | {Parser} = require lib+'parser' 9 | {constant, isArray, str} = require lib+'parser/base' 10 | taiji = require lib+'taiji' 11 | {realCode} = require lib+'utils' 12 | 13 | compile = (code) -> 14 | head = 'taiji language 0.1\n' 15 | realCode taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 16 | 17 | compileNoOptimize = (code) -> 18 | head = 'taiji language 0.1\n' 19 | realCode taiji.compileNoOptimize(head+code, taiji.rootModule, taiji.builtins, {}) 20 | 21 | describe "compile dyanmic syntax: ", -> 22 | describe "compile parser attribute: ", -> 23 | it 'should compile %xyz[0]()', -> 24 | expect(compile('%xyz[0]()')).to.have.string "__$taiji_$_$parser__.xyz[0]()" 25 | it 'should compile %cursor', -> 26 | expect(compile('%cursor')).to.have.string "__$taiji_$_$parser__.cursor" 27 | it 'should compile %char()', -> 28 | expect(compile('%char()')).to.have.string "__$taiji_$_$parser__.char()" 29 | 30 | describe "parsing time evaluation: ", -> 31 | it 'should compile %% 1', -> 32 | expect(compile('%% 1')).to.have.string "1" 33 | it 'should compile %% %cursor()', -> 34 | expect(compile('%% %cursor()')).to.have.string "31" 35 | it 'should compile %% %clause()', -> 36 | expect(compile('%% %clause(), 1')).to.have.string "1" 37 | 38 | describe "parsing time evaluation macro %/: ", -> 39 | it 'should compile %/ cursor', -> 40 | expect(compile('%/ cursor')).to.have.string "function () {\n return cursor;\n }" 41 | it 'should compile %/ cursor', -> 42 | expect(compile('%/ cursor()')).to.have.string "30" 43 | it 'should compile %/ clause(), 1', -> 44 | expect(compile('%/ clause(), 1')).to.have.string "1" 45 | it 'should compile %/ clause(), 1', -> 46 | expect(compile('%/ clause(), print 1')).to.have.string "console.log(1)" 47 | 48 | describe "macro %! used by %!: ", -> 49 | it 'should compile %! cursor()', -> 50 | expect(compile('%! cursor()')).to.have.string "30" 51 | it 'should compile %! char()', -> 52 | expect(compile('%! char()')).to.have.string "true" 53 | 54 | describe "%-then statement: ", -> 55 | nit 'should compile % xyz then x = abc', -> 56 | expect(compile('% xyz then x = abc')).to.have.string "[% [xyz] [then \"= x abc\"]]" 57 | -------------------------------------------------------------------------------- /bootstrap/test/parser/testdynamicgrammar.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../../lib/' 8 | {str, extend} = require lib+'utils' 9 | taiji = require lib+'taiji' 10 | 11 | describe "parse dyanmic syntax: ", -> 12 | head = 'taiji language 0.1\n' 13 | parse = (text) -> 14 | env = taiji.initEnv(taiji.builtins, taiji.rootModule, {}) 15 | parser = env.parser 16 | x = parser.parse(head+text, parser.module, 0, env) 17 | str x.body 18 | it 'should parse % xyz then anything here', -> 19 | expect(parse('% xyz then anything here')).to.equal "[object Object]" 20 | it 'should parse % cursor() then anything here', -> 21 | expect(parse('% cursor() then x = abc')).to.equal "35" 22 | it 'should parse % text then anything here', -> 23 | expect(parse('% text then anything here')).to.equal "taiji language 0.1\n% text then anything here" 24 | it 'should parse %% 1', -> 25 | expect(parse('%% 1')).to.equal "1" 26 | it 'should parse %/ %cursor', -> 27 | expect(parse('%/ %cursor')).to.equal "function () {\n return cursor;\n }" 28 | it 'should parse %/ cursor()', -> 29 | expect(parse('%/ cursor()')).to.equal "30" 30 | it 'should parse %/ clause(), print 1', -> 31 | expect(parse('%/ clause(), print 1')).to.equal "[print 1]" 32 | -------------------------------------------------------------------------------- /bootstrap/test/testcommand.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | 6 | lib = '../lib/' 7 | command = require lib+'command' 8 | 9 | command.testing = true 10 | 11 | describe 'test command:', -> 12 | describe "taiji command utilities: ", -> 13 | describe "taiji information: ", -> 14 | it 'should display taiji version', -> 15 | command.opts = {version: true} 16 | x = command.run() 17 | expect(x).to.equal true 18 | it 'should display taiji help information', -> 19 | command.opts = {help: true} 20 | x = command.run() 21 | expect(x).to.equal true 22 | 23 | parse = (outputPath, filePath) -> 24 | command.opts = {output: outputPath, parse:true, arguments:[filePath]} 25 | command.run() 26 | 27 | transform = (outputPath, filePath) -> 28 | command.opts = {output: outputPath, transform:true, arguments:[filePath]} 29 | command.run() 30 | 31 | compile = (outputPath, filePath) -> 32 | command.opts = {output: outputPath, compile:true, arguments:[filePath]} 33 | command.run() 34 | 35 | describe "parse and compile: ", -> 36 | describe "samples: ", -> 37 | it 'parse temp.tj', -> expect(parse 'samples-js/parse', 'samples/temp.tj').to.deep.equal [undefined] 38 | it 'transform temp.tj', -> expect(transform 'samples-js/transform', 'samples/temp.tj').to.deep.equal [undefined] 39 | it 'compile temp.tj', -> expect(compile 'samples-js', 'samples/temp.tj').to.deep.equal [undefined] 40 | it 'parse hello.tj', -> expect(parse 'samples-js/parse', 'samples/hello.tj').to.deep.equal [undefined] 41 | it 'compile hello.tj', -> expect(compile 'samples-js', 'samples/hello.tj').to.deep.equal [undefined] 42 | it 'parse demo.tj', -> expect(parse 'samples-js/parse', 'samples/demo.tj').to.deep.equal [undefined] 43 | it 'compile demo.tj', -> expect(compile 'samples-js', 'samples/demo.tj').to.deep.equal [undefined] 44 | it 'compile meta.tj', -> expect(compile 'samples-js', 'samples/meta.tj').to.deep.equal [undefined] 45 | it 'parse sample.tj', -> expect(parse 'samples-js/parse', 'samples/sample.tj').to.deep.equal [undefined] 46 | it 'compile sample.tj', -> expect(compile 'samples-js', 'samples/sample.tj').to.deep.equal [undefined] 47 | it 'compile blockcomment.tj', -> expect(compile 'samples-js', 'samples/blockcomment.tj').to.deep.equal [undefined] 48 | it 'parse block.tj', -> expect(parse 'samples-js', 'samples/block.tj').to.deep.equal [undefined] 49 | it 'compile block.tj', -> expect(compile 'samples-js', 'samples/block.tj').to.deep.equal [undefined] 50 | it 'parse indent-then-else.tj', -> expect(parse 'samples-js/parse', 'samples/indent-then-else.tj').to.deep.equal [undefined] 51 | it 'compile indent-then-else.tj', -> expect(compile 'samples-js', 'samples/indent-then-else.tj').to.deep.equal [undefined] 52 | it 'parse macros.tj', -> expect(parse 'samples-js/parse', 'samples/macros.tj').to.deep.equal [undefined] 53 | it 'compile macros.tj', -> expect(compile 'samples-js', 'samples/macros.tj').to.deep.equal [undefined] 54 | it 'compile square-macro.tj', -> expect(compile 'samples-js', 'samples/square-macro.tj').to.deep.equal [undefined] 55 | it 'compile let.tj', -> expect(compile 'samples-js', 'samples/let.tj').to.deep.equal [undefined] 56 | it 'compile loop.tj', -> expect(compile 'samples-js', 'samples/loop.tj').to.deep.equal [undefined] 57 | it 'compile nodeserver.tj', -> expect(compile 'samples-js', 'samples/nodeserver.tj').to.deep.equal [undefined] 58 | it 'parse snippets.tj', -> expect(parse 'samples-js', 'samples/snippets.tj').to.deep.equal [undefined] 59 | it 'compile snippets.tj', -> expect(compile 'samples-js', 'samples/snippets.tj').to.deep.equal [undefined] 60 | it 'compile ellipsis.tj', -> expect(compile 'samples-js', 'samples/ellipsis.tj').to.deep.equal [undefined] 61 | it 'compile include.tj', -> expect(compile 'samples-js', 'samples/include.tj').to.deep.equal [undefined] 62 | it 'parse import.tj', -> expect(parse 'samples-js', 'samples/import.tj').to.deep.equal [undefined] 63 | it 'compile import.tj', -> expect(compile 'samples-js', 'samples/import.tj').to.deep.equal [undefined] 64 | it 'parse democlass.tj', -> expect(parse 'samples-js', 'samples/democlass.tj').to.deep.equal [undefined] 65 | it 'compile democlass.tj', -> expect(compile 'samples-js', 'samples/democlass.tj').to.deep.equal [undefined] 66 | 67 | describe "parse and compile samples/bootstrap: ", -> 68 | it 'parse require.tj', -> expect(parse 'samples-js/bootstrap/parse', 'samples/bootstrap/require.tj').to.deep.equal [undefined] 69 | it 'compile require.tj', -> expect(compile 'samples-js/bootstrap', 'samples/bootstrap/require.tj').to.deep.equal [undefined] 70 | it 'parse taijilang.tj', -> expect(parse 'samples-js/bootstrap/parse', 'samples/bootstrap/taijilang.tj').to.deep.equal [undefined] 71 | it 'compile taijilang.tj', -> expect(parse 'samples-js/bootstrap', 'samples/bootstrap/taijilang.tj').to.deep.equal [undefined] 72 | it 'compile repl.tj', -> expect(compile 'samples-js/bootstrap', 'samples/bootstrap/repl.tj').to.deep.equal [undefined] 73 | 74 | describe "parse and compile taiji-libraries: ", -> 75 | it 'parse macros.tj', -> expect(parse 'taiji-libraries-js/parse', 'taiji-libraries/macros.tj').to.deep.equal [undefined] 76 | it 'compile macros.tj', -> expect(compile 'taiji-libraries-js', 'taiji-libraries/macros.tj').to.deep.equal [undefined] 77 | it 'parse class@.tj', -> expect(parse 'taiji-libraries-js/parse', 'taiji-libraries/class@.tj').to.deep.equal [undefined] 78 | it 'compile class@.tj', -> expect(compile 'taiji-libraries-js', 'taiji-libraries/class@.tj').to.deep.equal [undefined] 79 | it 'compile browser.tj', -> expect(compile 'taiji-libraries-js', 'taiji-libraries/browser.tj').to.deep.equal [undefined] 80 | it 'compile html.tj', -> expect(compile 'taiji-libraries-js', 'taiji-libraries/html.tj').to.deep.equal [undefined] 81 | it 'parse prelude.tj', -> expect(parse 'taiji-libraries-js', 'taiji-libraries/prelude.tj').to.deep.equal [undefined] 82 | 83 | run = (filePath) -> 84 | command.opts = {run:true, arguments:[filePath]} 85 | command.run() 86 | 87 | describe "command run: ", -> 88 | it 'hello.tj', -> expect(run 'samples/hello.tj').to.deep.equal [undefined] 89 | it 'ellipsis.tj', -> expect(run 'samples/ellipsis.tj').to.deep.equal [undefined] 90 | -------------------------------------------------------------------------------- /bootstrap/test/testeval.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../lib/' 8 | taiji = require lib+'taiji' 9 | 10 | evaltj = (code) -> 11 | head = 'taiji language 0.1\n' 12 | taiji.eval(head+code, taiji.rootModule, taiji.builtins, {}) 13 | 14 | describe "eval: ", -> 15 | describe "eval simple: ", -> 16 | it 'should eval 1', -> 17 | expect(evaltj('1')).to.equal 1 18 | it 'should eval \'a\'', -> 19 | expect(evaltj("'a'")).to.equal 'a' 20 | it 'should eval if 1 then 2', -> 21 | expect(evaltj("if 1 then 2")).to.equal 2 22 | it 'should eval ~ 2', -> 23 | expect(evaltj("~ 2")).to.equal 2 24 | it 'should eval 1+1', -> 25 | expect(evaltj("1+1")).to.equal 2 26 | 27 | describe "statement: ", -> 28 | it 'should eval a=1', -> 29 | expect(evaltj("a=1")).to.equal 1 30 | it 'should eval a=1; a+a', -> 31 | expect(evaltj("a=1; a+a")).to.equal 2 32 | it 'should eval let a=1 then let a = 2 then a+a', -> 33 | expect(evaltj("let a=1 then let a = 2 then a+a")).to.equal 4 34 | 35 | describe "eval 2", -> 36 | it 'should eval "a"', -> 37 | expect(evaltj('"a"')).to.equal 'a' 38 | -------------------------------------------------------------------------------- /bootstrap/test/testmodule.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | nit = -> 7 | 8 | path = require 'path' 9 | lib = '../lib/' 10 | {Parser} = require lib+'parser' 11 | {constant, isArray, str} = require lib+'parser/base' 12 | {} = require lib+'compiler/compile' 13 | taiji = require lib+'taiji' 14 | TaijiModule = require lib+'module' 15 | {realCode} = require lib+'utils' 16 | 17 | compile = (code) -> 18 | head = 'taiji language 0.1\n' 19 | realCode taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 20 | 21 | run = (code) -> 22 | head = 'taiji language 0.1\n' 23 | code = taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 24 | str eval code 25 | 26 | describe "taiji module: ", -> 27 | describe "path: ", -> 28 | it '__dirname', -> 29 | expect(__dirname).to.match /test/ 30 | it '__filename', -> 31 | expect(__filename).to.match /test\\testmodule.js/ 32 | it 'process.cwd', -> 33 | expect(process.cwd()).to.match /taijilang/ 34 | it 'process.execPath', -> 35 | expect(process.execPath).to.match /nodejs\\node/ 36 | it 'process.execArgv', -> 37 | expect(process.execArgv).to.deep.equal [] 38 | it 'process.env', -> 39 | #console.log process.env 40 | expect(process.env['TAIJILANG_PATH']).to.match /taijilang/ 41 | expect(process.env['taijilang_path']).to.match /taijilang/ 42 | 43 | describe 'new module: ', -> 44 | taijiModule = new TaijiModule('f:\\taijilang\\lib\\taiji.tj', null) 45 | it 'new TaijiModule', -> 46 | expect(taijiModule.basePath).to.match /lib/ 47 | expect(str taijiModule.modulePaths).to.match /taiji-libraries/ 48 | it 'should findPath', -> 49 | childModule = new TaijiModule('f:\\taijilang\\samples\\hello.tj', taijiModule) 50 | expect(childModule.basePath).to.equal 'f:\\taijilang\\samples' 51 | expect(childModule.findPath('.\\sample.tj')).to.equal 'f:\\taijilang\\samples\\sample.tj' 52 | expect(childModule.findPath('html.tj')).to.equal 'f:\\taijilang\\taiji-libraries\\html.tj' 53 | 54 | describe 'include!', -> 55 | it 'include! "./hello.tj"', -> 56 | expect(run("include! '../samples/hello.tj'")).to.equal "hello taiji" 57 | -------------------------------------------------------------------------------- /bootstrap/test/testprotoconstructor.js: -------------------------------------------------------------------------------- 1 | var chai = require("chai"); 2 | var expect = chai.expect; 3 | var iit = it.only; 4 | var idescribe = describe.only; 5 | var ndescribe = function() {}; 6 | var lib = '../lib/'; 7 | var _ref = require(lib + 'utils'), str = _ref.str, extend = _ref.extend; 8 | var taiji = require(lib + 'taiji'); 9 | 10 | describe("prototype constructor: ", function() { 11 | it('should constructor and instanceof', function () { 12 | var A = function(){} 13 | var B = function(){} 14 | b = new B() 15 | expect(b.constructor).to.equal(B); 16 | expect(b instanceof B).to.be.ok 17 | }); 18 | it('should derived constructor and instanceof', function () { 19 | var A = function(){} 20 | var B = function(){} 21 | function ctor() { this.constructor = B; } 22 | ctor.prototype = A.prototype; 23 | B.prototype = new ctor; 24 | b = new B() 25 | expect(b.constructor).to.equal(B); 26 | expect(b instanceof B).to.be.ok 27 | expect(b instanceof A).to.be.ok 28 | }); 29 | it('should inherit without ctor', function () { 30 | var A = function(){} 31 | var B = function(){} 32 | B.prototype = A.prototype; 33 | b = new B() 34 | expect(b.constructor).to.not.equal(B); 35 | expect(b.constructor).to.equal(A); 36 | expect(b instanceof B).to.be.ok 37 | expect(b instanceof A).to.be.ok 38 | }); 39 | }); -------------------------------------------------------------------------------- /bootstrap/test/testshell.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | 6 | require('shelljs/global') 7 | 8 | describe "taiji shell command: ", -> 9 | describe "experiment with shelljs: ", -> 10 | it 'should pwd', -> 11 | x = pwd() 12 | expect(x).to.match /taijilang/ 13 | 14 | it 'should display node version', -> 15 | x = exec('node --version', {silent:true}).output 16 | expect(x).to.equal "v0.10.22\r\n" 17 | 18 | it 'should display taiji version', -> 19 | x = exec('node bin/taiji -v', {silent:true}).output 20 | expect(x).to.equal "taiji version 0.1.0\n" 21 | 22 | describe "parse: ", -> 23 | it 'should parse hello.tj', -> 24 | x = exec('node bin/taiji -o samples-js --parse samples/hello.tj', {silent:true}).output 25 | expect(x).to.equal "" 26 | 27 | describe "compile file: ", -> 28 | it 'should compile hello.tj', -> 29 | x = exec('node bin/taiji -o samples-js -c samples/hello.tj', {silent:true}).output 30 | expect(x).to.equal "" 31 | it 'should compile sample.tj', -> 32 | x = exec('node bin/taiji -o samples-js -c samples/sample.tj', {silent:true}).output 33 | expect(x).to.equal "" 34 | it 'should compile loop.tj', -> 35 | x = exec('node bin/taiji -o samples-js -c samples/loop.tj', {silent:true}).output 36 | expect(x).to.equal "" 37 | 38 | describe "run: ", -> 39 | it 'should run hello.tj', -> 40 | x = exec('node bin/taiji samples/hello.tj', {silent:true}).output 41 | expect(x).to.equal "hello taiji\n" 42 | it 'should run sample.tj', -> 43 | x = exec('node bin/taiji samples/sample.tj', {silent:true}).output 44 | expect(x).to.equal "1\n7\n77\n77\n2\n2 3\n2\n2\n1\n2\n" 45 | -------------------------------------------------------------------------------- /bootstrap/test/testutils.tj: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../lib/' 8 | {isTaiji, baseFileName} = utils = require lib+'utils' 9 | 10 | describe "utils.coffee: ", -> 11 | describe "isTaiji filename: ", -> 12 | it ' 1.tj', -> 13 | expect(isTaiji '1.tj').to.equal true 14 | it ' 1.taiji', -> 15 | expect(isTaiji '1.taiji').to.equal true 16 | it ' 1.TAIJI', -> 17 | expect(isTaiji '1.TAIJI').to.equal false 18 | it ' 1.taiji.json', -> 19 | expect(isTaiji '1.taiji.json').to.equal true 20 | it ' 1.tj.json', -> 21 | expect(isTaiji '1.tj.json').to.equal true 22 | 23 | describe " baseFileName: ", -> 24 | it ' 1.tj', -> 25 | expect(baseFileName '1.tj', true).to.equal '1' 26 | it ' x\\1.tj', -> 27 | expect(baseFileName 'x\\1.tj', true, true).to.equal '1' 28 | it ' 1.taiji', -> 29 | expect(baseFileName '1.taiji', true).to.equal '1' 30 | it ' x\\1.taiji', -> 31 | expect(baseFileName 'x\\1.taiji', true, true).to.equal '1' 32 | it ' x//1.taiji', -> 33 | expect(baseFileName 'x//1.taiji', true).to.equal '1' 34 | it ' 1.taiji.json', -> 35 | expect(baseFileName '1.taiji.json', true).to.equal '1' 36 | it ' 1.tj.json', -> 37 | expect(baseFileName '1.tj.json', true).to.equal '1' 38 | -------------------------------------------------------------------------------- /doc/en/informal document status declaration.md: -------------------------------------------------------------------------------- 1 | Informal document status declaration 2 | 3 | All of documents in this folder are in the draft state, may be outdated, incomplete, inaccurate or even incorrect. Before publishing a new declaration, all of these documents currently should be treated as an informal reference, not as any basis, the readers please note this declaration. -------------------------------------------------------------------------------- /doc/en/introduction.md: -------------------------------------------------------------------------------- 1 | # taijilang 2 | 3 | ## A language with meta language! 4 | Taijilang is a new general powerful programming language, with flexibility, good readability, ease of use. Taijilang will have more customizability and scalability than all other existing programming languages. 5 | 6 | In general, the features of Taijilang can be summed up: more powerful macro than in lisp, more important white space than in the indentation syntax of python, more general preprocess than in C, broader meta compilation than metalua, more flexible dialect feature than rebol, more optimized object code than in coffee-script. Listed below are the specific features of Taijilang: 7 | 8 | * Compiled to javascript language 9 |    Taijilang may expand to use other languages ​​as the target language in the future . 10 | * Flexible friendly syntax 11 |    Taijilang have fine and flexible syntax control, e.g. indentation grammar and other kind of use of white spaces to help the reading; spaces can change the precedence of operators; flexible multi-line strings in which the programmer can control interpolation, escaping freely, and so on 12 | * Everything are expressions 13 |    Similar to CoffeeScript, assignment, if, switch, while, for statement are all expressions. Further, in Taijilang, return, break statement has also been treated as expressions. Less distinction between statements and expressions will give us greater freedom to organize the program, which I fully understood while I develop the parser for Taijilang with coffee-script, it is exactly because of the syntax features of treating assignment and function definition in coffee-script language that I was inspired to find a new method to write parser by hand, which is the key to the dynamic parser of Taijilang (see the [peasy project](https://www.github.com/chaosim/peasy ) ). 14 | * Macro 15 |    Based on quasi quoted list, Taijilang have macro simliar to lisp. Combined with a friendly, extendable dynamic syntax, macro in Taijilang becomes even more powerful than lisp. 16 | * Meta Language 17 |    Any expression can be evaluated at compile time to control the compilation process and object code. This is similar to preprocess the C language, but more general. The macro and meta-language features can greatly improve expressionability, and help to write more optimized software. 18 | * Customizable and extensible syntax 19 |    Taijilang syntax can be customized and extended from the multi-level, including the re-definition of grammatical elements, define new operator expressions, set a new operator, and so on. Any keywords and symbols in Taijilang can be redefined by macros or functions. 20 | * Modulization 21 |    Different from most other languages ​​compiled to javascript, Taijilang ​​have its own modular system. 22 | The programmers can organize programs by modules and packages, and release libraries or frameworks in Taijilang. 23 | * Optimized object code 24 |    Contrast to other languages (such as coffee-script) compiled to javascript, Taijilang completely avoids generating closure function and function call while transforms expressions to javascript construct; Taijilang also deletes operation which has no effect, do recursion optimization, including but not limited to tail recursion optimization on, and so on. 25 | 26 | 27 | #### taijilang was inspired by lisp, scheme, LambdaProlog, curry, haskell, c, python, javascript, coffeescript, pyprolog, yieldProlog, dao, daonode, peasy, lispyscript and littlelisp. 28 | 29 | #### Community 30 | google groups: [taijilang -- https://groups.google.com/forum/#!forum/taijilang](https://groups.google.com/forum/#!forum/taijilang). 31 | 32 | ### Contributors 33 | [曹星明Caoxingming](https://github.com/taijilang). 34 | -------------------------------------------------------------------------------- /doc/en/the zen of taiji.md: -------------------------------------------------------------------------------- 1 | ### the zen of taiji 2 | 3 | Being and Not-being grow out of one another, 4 | Difficult and easy complete one another, 5 | How to distinct more from less, good from bad? 6 | What is right or wrong, and what is cause and effect? 7 | When people interact with the machine, 8 | the habits come into being naturally. 9 | The dao and name being told are never eternal, 10 | let us exporle one that rules all. 11 | 12 | 13 | -------------------------------------------------------------------------------- /doc/zh-cn/太极语言规范.md: -------------------------------------------------------------------------------- 1 | 非正式文档状态声明 2 | 3 | 本文件夹保护的所有文档都处于草稿状态,可能已过时,不完整,不准确甚至不正确。在发布新的声明之前,所有文档目前权当非正式的参考,不作为任何依据,阅读者敬请留意此声明。 4 | 5 | 概念 6 | 7 | 解析过程 8 | 9 | 内部表示 10 | 11 | json格式 12 | 13 | 文字量 14 | 15 | 文字量,字面量,不变量,常量,常数 16 | 17 | 字符串,数字,布尔值(true, false),文字表,undefined, null 18 | 19 | 值 20 | 函数、对象(字典,hash,map),字符串,数字、 21 | 22 | 符号 23 | 常量符号,简称常量 24 | 变量符号,简称变量 25 | 26 | 模板 27 | 28 | 列表 29 | 30 | 命令式 31 | 32 | 命令 33 | 34 | 运算式 35 | 36 | 回引式表 37 | 38 | 元语言 39 | 40 | 元函数 41 | 42 | 宏 43 | 44 | 目标语言 45 | 46 | 执行过程 47 | 也称为求解过程 48 | 列表的第一个元素称为列表头,表头,头元素 49 | 列表从第二个元素直到最后一个元素称为列表尾,或者表尾。 50 | taiji.solve = function(exp, env, taiji): 51 | 如果exp是列表, 52 | 如果表头head是符号,则从env查找它的值,赋为val 53 | 如果head是函数,则先求表尾各值,则返回head(exp, env, taiji) 54 | 如果head是列表,则令exp[0]=taiji.solve(head, env),然后返回taiji.solve(exp, env) 55 | 如果head是函数,则返回head(表尾, env, taiji) 56 | 否则返回exp 57 | 如果exp是符号,则以之从env中查找值 58 | 否则原值返回exp。 59 | 60 | 编译过程 61 | 62 | 语法 对空白敏感的基于缩进的语法 63 | 用匹配的中括号封闭的嵌套列表式 64 | 简称s表达式(s表达式),或者简称括号式 65 | [print [+ a b]] 66 | 67 | 缩进块表达式 68 | 不是依据括号,而是依据行首空白决定表达式的嵌套结构。以这种方式组织的一段代码称为缩进表达式 69 | 简称缩进表达式,或者叫块表达式 70 | 71 | 冒号引导的缩进嵌套表达式 72 | 简称冒号表达式 73 | if [undefined? a] then print b 74 | if undefined?(a) then print b 75 | 76 | 以分号结束的行内嵌表达式 77 | 简称行内式,或者称为分号式 78 | 79 | javascript风格的运算表达式(圆括号表达式) 80 | 简称js表达式 81 | (1) (1+2) (-a+b) (-a) 82 | 83 | 调用记法以及参数列表 84 | a() a(1,2) a(1 2) 85 | 左括号紧靠被调用者,中间没有空白。如果有空白将会成为一个独立的js表达式 86 | 87 | 属性访问和索引 88 | a.b #afds.b afd?.b 89 | a.1 a.2 a&/b a[1] a[1,2] 90 | 91 | 以单引号开始的表达式 92 | 简称单引号式,或单引式 93 | '[a b] 94 | 95 | 以回引号开始的表达式 96 | 单引号后面紧跟一中括号。 97 | 简称回引号式,或回引式。 98 | `[a b] 99 | 回引式的优先级低于块表达式 100 | 101 | 以符号^引导的消除回引效果的转义式 102 | 消回引号式,或者叫消回引式,消引号式,消引式。 103 | 符号^称为消引符号 104 | 逗号必须紧靠后面的表达式,其中不能有空白或其它字符。逗号前面必须有一个以上空白字符。 105 | ^something 106 | `[a ^b] 107 | 108 | 以符号^&消除列表回引效果的转义式 109 | 消回引号列表式,简称消列表式 110 | 逗号及地址号^&称为消列表符号 111 | 112 | ^&some-list 113 | `[a ^&b] 114 | 115 | ^&称为消列表符号 116 | 117 | 118 | 消引式及消列表式的优先级高于块表达式。 119 | ^&if a then a else b 120 | 将产生[["unquote-splice", "if"], "a", "then", "#a", "else" "b"] 121 | ^&[if a then a else b] 122 | 将产生["unquote-splice", ["if", "a", ["then", "#a"], ["else" "b"]] 123 | 124 | -------------------------------------------------------------------------------- /doc/zh-cn/非正式文档状态声明.md: -------------------------------------------------------------------------------- 1 | 非正式文档状态声明 2 | 3 | 本文件夹保护的所有文档都处于草稿状态,可能已过时,不完整,不准确甚至不正确。在发布新的声明之前,所有文档目前权当非正式的参考,不作为任何依据,阅读者敬请留意此声明。 -------------------------------------------------------------------------------- /gulpfile.coffee: -------------------------------------------------------------------------------- 1 | gulp = require('gulp') 2 | gutil = require 'gulp-util' 3 | changed = require('gulp-changed') 4 | cache = require('gulp-cached') 5 | plumber = require('gulp-plumber') 6 | clean = require('gulp-clean') 7 | rename = require("gulp-rename") 8 | coffee = require ('gulp-coffee') 9 | mocha = require('gulp-mocha') 10 | runSequence = require('run-sequence') 11 | 12 | task = gulp.task.bind(gulp) 13 | watch = gulp.watch.bind(gulp) 14 | src = gulp.src.bind(gulp) 15 | dest = gulp.dest.bind(gulp) 16 | from = (source, options={dest:folders_dest, cache:'cache'}) -> 17 | options.dest ?= folders_dest 18 | options.cache ?= 'cache' 19 | src(source).pipe(changed(options.dest)).pipe(cache(options.cache)).pipe(plumber()) 20 | GulpStream = src('').constructor 21 | GulpStream::to = (dst) -> @pipe(dest(dst))#.pipe(livereload(tinylrServer)) 22 | GulpStream::pipelog = (obj, log=gutil.log) -> @pipe(obj).on('error', log) 23 | 24 | folders_src = 'src/' 25 | folders_coffee = folders_src 26 | folders_dest = './' 27 | 28 | FromStream = from('').constructor 29 | FromStream::to = (dst) -> @pipe(dest(dst))#.pipe(livereload(tinylrServer)) 30 | FromStream::pipelog = (obj, log=gutil.log) -> @pipe(obj).on('error', log) 31 | 32 | rootOf = (path) -> path.slice(0, path.indexOf('')) 33 | midOf = (path) -> path.slice(path.indexOf('')+1, path.indexOf('*')) 34 | 35 | distributing = false 36 | 37 | # below will put output js files in wrong directory structure!!! 38 | # coffee: [coffeeroot+'*.coffee', coffeeroot+'samples/**/*.coffee', coffeeroot+'test/**/*.coffee'] 39 | # use the code below to solve this problem 40 | patterns = (args...) -> 41 | for arg in args 42 | if typeof arg =='string' then pattern(arg) 43 | else arg 44 | gulpto = (destbase, args...) -> 45 | for arg in args 46 | if typeof arg =='string' then pattern(arg, destbase) 47 | else arg 48 | pattern = (src, destbase, options) -> new Pattern(src, destbase, options) 49 | class Pattern 50 | constructor: (@src, @destbase, options={}) -> 51 | if typeof destbase=='object' then options = destbase; @destbase = undefined 52 | srcRoot = rootOf(@src) 53 | if not @destbase then @destbase = rootOf(@src) 54 | if not options.desttail? then @desttail = midOf(@src) 55 | if @desttail then @dest = @destbase+@desttail 56 | else @dest = @destbase 57 | 58 | cleanFolders = for p in 'lib bin test samples-js taiji-libraries-js bootstrap-js'.split(' ') then folders_dest+p 59 | task 'clean', -> src(cleanFolders, {read:false}).pipe(clean()) 60 | 61 | files_copy = (folders_src+name for name in ['**/*.js', '**/*.json', '**/*.html', '**/*.css']) 62 | task 'copy', -> from(files_copy, {cache:'copy'}).to(folders_dest) 63 | 64 | task 'coffee', -> 65 | from(['src/**/*.coffee', '!src/bin**/*.coffee'], {cache:'coffee'}).pipelog(coffee({bare: true})).to('./lib') 66 | from(['src/bin**/*.coffee'], {cache:'coffee'}).pipelog(coffee({bare: true})).to('./') 67 | from(['test/**/*.coffee', '!src/bin**/*.coffee'], {cache:'coffee'}).pipelog(coffee({bare: true})).to('./test-build') 68 | 69 | task 'rename', -> from(folders_dest+'bin/*.js').pipe(rename((path) -> path.extname = "")).to(folders_dest+'bin') 70 | 71 | task 'make', (callback) -> distributing = false; runSequence('clean', ['copy', 'coffee'], 'rename', callback) 72 | 73 | files_mocha = folders_dest+'test-build/**/*.js' 74 | 75 | onErrorContinue = (err) -> console.log(err.stack); @emit 'end' 76 | task 'mocha', -> src(files_mocha).pipe(mocha({reporter: 'spec'})).on("error", onErrorContinue) 77 | task 'test', (callback) -> runSequence('make', 'mocha', callback) 78 | task 'default',['test'] -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | require('coffee-script/register'); 2 | require('./gulpfile.coffee'); -------------------------------------------------------------------------------- /lib/browser.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | this file is based on coffeescript/src/browser.coffee(https://github.com/jashkenas/coffeescript) 4 | Thanks to Jeremy Ashkenas 5 | Some stuffs is added or modified for taiji langauge. 6 | this file is not tested in taiji still. 7 | */ 8 | 9 | /* 10 | Copyright (c) 2009-2014 Jeremy Ashkenas 11 | Copyright (c) 2014-2015 Caoxingming 12 | 13 | Permission is hereby granted, free of charge, to any person 14 | obtaining a copy of this software and associated documentation 15 | files (the "Software"), to deal in the Software without 16 | restriction, including without limitation the rights to use, 17 | copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the 19 | Software is furnished to do so, subject to the following 20 | conditions: 21 | 22 | The above copyright notice and this permission notice shall be 23 | included in all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 27 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 29 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 30 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 32 | OTHER DEALINGS IN THE SOFTWARE. 33 | */ 34 | var compile, runScripts, taiji, 35 | __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 36 | 37 | taiji = require('./taiji'); 38 | 39 | taiji.require = require; 40 | 41 | compile = taiji.compile; 42 | 43 | taiji["eval"] = function(code, options) { 44 | if (options == null) { 45 | options = {}; 46 | } 47 | if (options.bare == null) { 48 | options.bare = true; 49 | } 50 | return eval(compile(code, options)); 51 | }; 52 | 53 | taiji.run = function(code, options) { 54 | if (options == null) { 55 | options = {}; 56 | } 57 | options.bare = true; 58 | options.shiftLine = true; 59 | return Function(compile(code, options))(); 60 | }; 61 | 62 | if (typeof window === "undefined" || window === null) { 63 | return; 64 | } 65 | 66 | if ((typeof btoa !== "undefined" && btoa !== null) && (typeof JSON !== "undefined" && JSON !== null) && (typeof unescape !== "undefined" && unescape !== null) && (typeof encodeURIComponent !== "undefined" && encodeURIComponent !== null)) { 67 | compile = function(code, options) { 68 | var js, v3SourceMap, _ref; 69 | if (options == null) { 70 | options = {}; 71 | } 72 | options.sourceMap = true; 73 | options.inline = true; 74 | _ref = taiji.compile(code, options), js = _ref.js, v3SourceMap = _ref.v3SourceMap; 75 | return "" + js + "\n//# sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//# sourceURL=taiji"; 76 | }; 77 | } 78 | 79 | taiji.load = function(url, callback, options, hold) { 80 | var xhr; 81 | if (options == null) { 82 | options = {}; 83 | } 84 | if (hold == null) { 85 | hold = false; 86 | } 87 | options.sourceFiles = [url]; 88 | xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new window.XMLHttpRequest(); 89 | xhr.open('GET', url, true); 90 | if ('overrideMimeType' in xhr) { 91 | xhr.overrideMimeType('text/plain'); 92 | } 93 | xhr.onreadystatechange = function() { 94 | var param, _ref; 95 | if (xhr.readyState === 4) { 96 | if ((_ref = xhr.status) === 0 || _ref === 200) { 97 | param = [xhr.responseText, options]; 98 | if (!hold) { 99 | taiji.run.apply(taiji, param); 100 | } 101 | } else { 102 | throw new Error("Could not load " + url); 103 | } 104 | if (callback) { 105 | return callback(param); 106 | } 107 | } 108 | }; 109 | return xhr.send(null); 110 | }; 111 | 112 | runScripts = function() { 113 | var execute, i, index, s, script, scripts, taijis, taijitypes, _fn, _i, _len; 114 | scripts = window.document.getElementsByTagName('script'); 115 | taijitypes = ['text/taiji']; 116 | taijis = (function() { 117 | var _i, _len, _ref, _results; 118 | _results = []; 119 | for (_i = 0, _len = scripts.length; _i < _len; _i++) { 120 | s = scripts[_i]; 121 | if (_ref = s.type, __indexOf.call(taijitypes, _ref) >= 0) { 122 | _results.push(s); 123 | } 124 | } 125 | return _results; 126 | })(); 127 | index = 0; 128 | execute = function() { 129 | var param; 130 | param = taijis[index]; 131 | if (param instanceof Array) { 132 | taiji.run.apply(taiji, param); 133 | index++; 134 | return execute(); 135 | } 136 | }; 137 | _fn = function(script, i) { 138 | var options; 139 | options = { 140 | literate: script.type === taijitypes[1] 141 | }; 142 | if (script.src) { 143 | return taiji.load(script.src, (function(param) { 144 | taijis[i] = param; 145 | return execute(); 146 | }), options, true); 147 | } else { 148 | options.sourceFiles = ['embedded']; 149 | return taijis[i] = [script.innerHTML, options]; 150 | } 151 | }; 152 | for (i = _i = 0, _len = taijis.length; _i < _len; i = ++_i) { 153 | script = taijis[i]; 154 | _fn(script, i); 155 | } 156 | return execute(); 157 | }; 158 | 159 | if (window.addEventListener) { 160 | window.addEventListener('DOMContentLoaded', runScripts, false); 161 | } else { 162 | window.attachEvent('onload', runScripts); 163 | } 164 | -------------------------------------------------------------------------------- /lib/compiler/package.json: -------------------------------------------------------------------------------- 1 | {"main":"compile.js"} -------------------------------------------------------------------------------- /lib/module.js: -------------------------------------------------------------------------------- 1 | var TaijiModule, exports, fs, hasOwnProperty, modulePaths, path, tryFile, tryPath, _realpathCache; 2 | 3 | fs = require('fs'); 4 | 5 | path = require('path'); 6 | 7 | hasOwnProperty = function(obj, prop) { 8 | return Object.prototype.hasOwnProperty.call(obj, prop); 9 | }; 10 | 11 | modulePaths = []; 12 | 13 | module.exports = exports = TaijiModule = function(filePath, parent) { 14 | this.parent = parent; 15 | this.exports = {}; 16 | if (!filePath) { 17 | if (this.parent) { 18 | this.filePath = this.parent.filePath; 19 | } else { 20 | this.filePath = __filename; 21 | } 22 | } else if (!this.parent) { 23 | this.filePath = filePath; 24 | } else { 25 | this.filePath = this.parent.findPath(filePath); 26 | } 27 | this.basePath = path.dirname(this.filePath); 28 | if (this.parent) { 29 | this.modulePaths = this.parent.modulePaths.slice(); 30 | this.modulePaths.unshift(path.resolve(this.basePath, '../taiji-libraries')); 31 | } else { 32 | this.modulePaths = modulePaths.slice(); 33 | this.modulePaths.unshift(path.resolve(this.basePath, '../taiji_modules')); 34 | } 35 | return this; 36 | }; 37 | 38 | TaijiModule._initPaths = function() { 39 | var i, path1, paths, splitter, _i, _len; 40 | if (process.env['TAIJILANG_PATH']) { 41 | splitter = process.platform === 'win32' ? ';' : ':'; 42 | paths = process.env['TAIJILANG_PATH'].split(splitter); 43 | for (i = _i = 0, _len = paths.length; _i < _len; i = ++_i) { 44 | path1 = paths[i]; 45 | paths[i] = path.resolve(path1, 'taiji-libraries'); 46 | } 47 | } else { 48 | paths = []; 49 | } 50 | return modulePaths = paths; 51 | }; 52 | 53 | TaijiModule._initPaths(); 54 | 55 | _realpathCache = {}; 56 | 57 | tryFile = function(requestPath) { 58 | var ex, stats; 59 | try { 60 | stats = fs.statSync(requestPath); 61 | if (stats && !stats.isDirectory()) { 62 | return fs.realpathSync(requestPath, _realpathCache); 63 | } 64 | } catch (_error) { 65 | ex = _error; 66 | return false; 67 | } 68 | }; 69 | 70 | tryPath = function(filePath, trailingSlash) { 71 | var filename, mainPath; 72 | if (!trailingSlash) { 73 | filename = tryFile(filePath); 74 | if (!filename && filePath.slice(-3) !== '.tj') { 75 | filename = tryFile(filePath + '.tj'); 76 | } 77 | } 78 | if (!filename) { 79 | mainPath = path.resolve(filePath, 'main.tj'); 80 | filename = tryFile(mainPath); 81 | } 82 | return filename; 83 | }; 84 | 85 | TaijiModule.matchPaths = function(request, paths) { 86 | var filename, path1, trailingSlash, _i, _len; 87 | trailingSlash = request.slice(-1) === '/'; 88 | for (_i = 0, _len = paths.length; _i < _len; _i++) { 89 | path1 = paths[_i]; 90 | if (filename = tryPath(path.resolve(path1, request), trailingSlash)) { 91 | return filename; 92 | } 93 | } 94 | }; 95 | 96 | TaijiModule.prototype.findPath = function(filePath) { 97 | var err, filename, paths, start, trailingSlash; 98 | if (filePath === '**evaluated taijilang code**') { 99 | return filePath; 100 | } 101 | if (fs.exists(filePath)) { 102 | return filePath; 103 | } 104 | start = filePath.substring(0, 2); 105 | if (start === './' || start === '.\\' || start === '..') { 106 | trailingSlash = filePath.slice(-1) === '/'; 107 | filename = tryPath(path.resolve(this.basePath, filePath), trailingSlash); 108 | } else { 109 | if (filePath.charAt(0) === '/') { 110 | paths = ['']; 111 | } else { 112 | paths = this.modulePaths; 113 | } 114 | filename = TaijiModule.matchPaths(filePath, paths); 115 | } 116 | if (!filename) { 117 | err = new Error("Cannot find module '" + filePath + "'"); 118 | err.code = 'MODULE_NOT_FOUND'; 119 | throw err; 120 | } 121 | return filename; 122 | }; 123 | -------------------------------------------------------------------------------- /lib/optparse.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | this file is based on coffeescript/src/optparse.coffee(https://github.com/jashkenas/coffeescript) 4 | Thanks to Jeremy Ashkenas 5 | Some stuffs is added or modified for taiji langauge. 6 | */ 7 | 8 | /* 9 | Copyright (c) 2009-2014 Jeremy Ashkenas 10 | Copyright (c) 2014-2015 Caoxingming 11 | 12 | Permission is hereby granted, free of charge, to any person 13 | obtaining a copy of this software and associated documentation 14 | files (the "Software"), to deal in the Software without 15 | restriction, including without limitation the rights to use, 16 | copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the 18 | Software is furnished to do so, subject to the following 19 | conditions: 20 | 21 | The above copyright notice and this permission notice shall be 22 | included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 26 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 28 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 29 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 31 | OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat; 34 | 35 | exports.OptionParser = OptionParser = (function() { 36 | function OptionParser(rules, banner) { 37 | this.banner = banner; 38 | this.rules = buildRules(rules); 39 | } 40 | 41 | OptionParser.prototype.parse = function(args) { 42 | var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len1, _ref; 43 | options = { 44 | "arguments": [] 45 | }; 46 | skippingArgument = false; 47 | originalArgs = args; 48 | args = normalizeArguments(args); 49 | for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { 50 | arg = args[i]; 51 | if (skippingArgument) { 52 | skippingArgument = false; 53 | continue; 54 | } 55 | if (arg === '--') { 56 | pos = originalArgs.indexOf('--'); 57 | options["arguments"] = options["arguments"].concat(originalArgs.slice(pos + 1)); 58 | break; 59 | } 60 | isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG)); 61 | seenNonOptionArg = options["arguments"].length > 0; 62 | if (!seenNonOptionArg) { 63 | matchedRule = false; 64 | _ref = this.rules; 65 | for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { 66 | rule = _ref[_j]; 67 | if (rule.shortFlag === arg || rule.longFlag === arg) { 68 | value = true; 69 | if (rule.hasArgument) { 70 | skippingArgument = true; 71 | value = args[i + 1]; 72 | } 73 | options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value; 74 | matchedRule = true; 75 | break; 76 | } 77 | } 78 | if (isOption && !matchedRule) { 79 | throw new Error("unrecognized option: " + arg); 80 | } 81 | } 82 | if (seenNonOptionArg || !isOption) { 83 | options["arguments"].push(arg); 84 | } 85 | } 86 | return options; 87 | }; 88 | 89 | OptionParser.prototype.help = function() { 90 | var letPart, lines, rule, spaces, _i, _len, _ref; 91 | lines = []; 92 | if (this.banner) { 93 | lines.unshift("" + this.banner + "\n"); 94 | } 95 | _ref = this.rules; 96 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 97 | rule = _ref[_i]; 98 | spaces = 15 - rule.longFlag.length; 99 | spaces = spaces > 0 ? repeat(' ', spaces) : ''; 100 | letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' '; 101 | lines.push(' ' + letPart + rule.longFlag + spaces + rule.description); 102 | } 103 | return "\n" + (lines.join('\n')) + "\n"; 104 | }; 105 | 106 | return OptionParser; 107 | 108 | })(); 109 | 110 | LONG_FLAG = /^(--\w[\w\-]*)/; 111 | 112 | SHORT_FLAG = /^(-\w)$/; 113 | 114 | MULTI_FLAG = /^-(\w{2,})/; 115 | 116 | OPTIONAL = /\[(\w+(\*?))\]/; 117 | 118 | buildRules = function(rules) { 119 | var tuple, _i, _len, _results; 120 | _results = []; 121 | for (_i = 0, _len = rules.length; _i < _len; _i++) { 122 | tuple = rules[_i]; 123 | if (tuple.length < 3) { 124 | tuple.unshift(null); 125 | } 126 | _results.push(buildRule.apply(null, tuple)); 127 | } 128 | return _results; 129 | }; 130 | 131 | buildRule = function(shortFlag, longFlag, description, options) { 132 | var match; 133 | if (options == null) { 134 | options = {}; 135 | } 136 | match = longFlag.match(OPTIONAL); 137 | longFlag = longFlag.match(LONG_FLAG)[1]; 138 | return { 139 | name: longFlag.substr(2), 140 | shortFlag: shortFlag, 141 | longFlag: longFlag, 142 | description: description, 143 | hasArgument: !!(match && match[1]), 144 | isList: !!(match && match[2]) 145 | }; 146 | }; 147 | 148 | normalizeArguments = function(args) { 149 | var arg, l, match, result, _i, _j, _len, _len1, _ref; 150 | args = args.slice(0); 151 | result = []; 152 | for (_i = 0, _len = args.length; _i < _len; _i++) { 153 | arg = args[_i]; 154 | if (match = arg.match(MULTI_FLAG)) { 155 | _ref = match[1].split(''); 156 | for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { 157 | l = _ref[_j]; 158 | result.push('-' + l); 159 | } 160 | } else { 161 | result.push(arg); 162 | } 163 | } 164 | return result; 165 | }; 166 | 167 | repeat = function(str, n) { 168 | var res; 169 | res = ''; 170 | while (n > 0) { 171 | if (n & 1) { 172 | res += str; 173 | } 174 | n >>>= 1; 175 | str += str; 176 | } 177 | return res; 178 | }; 179 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | {"main":"taiji.js"} -------------------------------------------------------------------------------- /lib/parser/base.js: -------------------------------------------------------------------------------- 1 | var BLOCK_COMMENT, BRACKET, CODE_BLOCK_COMMENT, CONCAT_LINE, CURVE, C_BLOCK_COMMENT, DATA_BRACKET, EOI, FUNCTION, HALF_DENT, HEAD_SPACES, IDENTIFIER, INDENT, INDENT_EXPRESSION, INLINE_COMMENT, INTERPOLATE_STRING, LINE_COMMENT, MODULE, MODULE_HEADER, NEWLINE, NON_INTERPOLATE_STRING, NUMBER, PAREN, PUNCT, REGEXP, SPACES, SPACES_INLINE_COMMENT, SPACE_COMMENT, STRING, SYMBOL, TAIL_COMMENT, UNDENT, charset, digitCharSet, digits, firstIdentifierChars, identifierCharSet, identifierChars, letterCharSet, letterDigits, letters, lowers, str, taijiIdentifierCharSet, taijiIdentifierChars, uppers, utils; 2 | 3 | utils = require('../utils'); 4 | 5 | exports.entity = utils.entity; 6 | 7 | exports.debug = utils.debug; 8 | 9 | exports.warn = utils.warn; 10 | 11 | exports.str = str = utils.str; 12 | 13 | exports.convertIdentifier = utils.convertIdentifier; 14 | 15 | exports.isArray = utils.isArray; 16 | 17 | exports.extend = utils.extend; 18 | 19 | exports.wrapInfo1 = utils.wrapInfo1; 20 | 21 | exports.wrapInfo2 = utils.wrapInfo2; 22 | 23 | exports.charset = charset = utils.charset; 24 | 25 | exports.digits = digits = '0123456789'; 26 | 27 | exports.lowers = lowers = 'abcdefghijklmnopqrstuvwxyz'; 28 | 29 | exports.uppers = uppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 30 | 31 | exports.letters = letters = lowers + uppers; 32 | 33 | exports.letterDigits = letterDigits = letters + digits; 34 | 35 | exports.letterDigitSet = charset(letterDigits); 36 | 37 | exports.firstIdentifierChars = firstIdentifierChars = '$_' + letters; 38 | 39 | exports.identifierChars = identifierChars = firstIdentifierChars + digits; 40 | 41 | exports.taijiIdentifierChars = taijiIdentifierChars = '!?' + identifierChars; 42 | 43 | exports.digitCharSet = digitCharSet = charset(exports.digits); 44 | 45 | exports.letterCharSet = letterCharSet = charset(exports.letters); 46 | 47 | exports.firstIdentifierCharSet = charset('$_' + letters); 48 | 49 | exports.identifierCharSet = identifierCharSet = charset(identifierChars); 50 | 51 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars); 52 | 53 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars); 54 | 55 | NUMBER = 1; 56 | 57 | STRING = 2; 58 | 59 | IDENTIFIER = 3; 60 | 61 | SYMBOL = 4; 62 | 63 | REGEXP = 5; 64 | 65 | HEAD_SPACES = 6; 66 | 67 | CONCAT_LINE = 7; 68 | 69 | PUNCT = 8; 70 | 71 | FUNCTION = 9; 72 | 73 | BRACKET = 10; 74 | 75 | PAREN = 11; 76 | 77 | DATA_BRACKET = 12; 78 | 79 | CURVE = 13; 80 | 81 | INDENT_EXPRESSION = 14; 82 | 83 | NEWLINE = 15; 84 | 85 | SPACES = 16; 86 | 87 | INLINE_COMMENT = 17; 88 | 89 | SPACES_INLINE_COMMENT = 18; 90 | 91 | LINE_COMMENT = 19; 92 | 93 | BLOCK_COMMENT = 20; 94 | 95 | CODE_BLOCK_COMMENT = 21; 96 | 97 | CONCAT_LINE = 22; 98 | 99 | MODULE_HEADER = 23; 100 | 101 | MODULE = 24; 102 | 103 | NON_INTERPOLATE_STRING = 25; 104 | 105 | INTERPOLATE_STRING = 26; 106 | 107 | INDENT = 27; 108 | 109 | UNDENT = 28; 110 | 111 | HALF_DENT = 29; 112 | 113 | EOI = 30; 114 | 115 | C_BLOCK_COMMENT = 31; 116 | 117 | SPACE_COMMENT = 32; 118 | 119 | TAIL_COMMENT = 33; 120 | 121 | exports.constant = { 122 | NUMBER: NUMBER, 123 | STRING: STRING, 124 | IDENTIFIER: IDENTIFIER, 125 | SYMBOL: SYMBOL, 126 | REGEXP: REGEXP, 127 | HEAD_SPACES: HEAD_SPACES, 128 | CONCAT_LINE: CONCAT_LINE, 129 | PUNCT: PUNCT, 130 | FUNCTION: FUNCTION, 131 | BRACKET: BRACKET, 132 | PAREN: PAREN, 133 | DATA_BRACKET: DATA_BRACKET, 134 | CURVE: CURVE, 135 | INDENT_EXPRESSION: INDENT_EXPRESSION, 136 | NEWLINE: NEWLINE, 137 | SPACES: SPACES, 138 | INLINE_COMMENT: INLINE_COMMENT, 139 | SPACES_INLINE_COMMENT: SPACES_INLINE_COMMENT, 140 | LINE_COMMENT: LINE_COMMENT, 141 | BLOCK_COMMENT: BLOCK_COMMENT, 142 | CODE_BLOCK_COMMENT: CODE_BLOCK_COMMENT, 143 | CONCAT_LINE: CONCAT_LINE, 144 | MODULE_HEADER: MODULE_HEADER, 145 | MODULE: MODULE, 146 | NON_INTERPOLATE_STRING: NON_INTERPOLATE_STRING, 147 | INTERPOLATE_STRING: INTERPOLATE_STRING, 148 | INDENT: INDENT, 149 | UNDENT: UNDENT, 150 | HALF_DENT: HALF_DENT, 151 | EOI: EOI, 152 | C_BLOCK_COMMENT: C_BLOCK_COMMENT, 153 | SPACE_COMMENT: SPACE_COMMENT, 154 | TAIL_COMMENT: TAIL_COMMENT 155 | }; 156 | -------------------------------------------------------------------------------- /lib/parser/package.json: -------------------------------------------------------------------------------- 1 | {"main":"parser.js"} -------------------------------------------------------------------------------- /lib/register.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | this file is based on coffeescript/src/register.coffee(https://github.com/jashkenas/coffeescript) 4 | Thanks to Jeremy Ashkenas 5 | Some stuffs is added or modified for taiji langauge. 6 | */ 7 | 8 | /* 9 | Copyright (c) 2009-2014 Jeremy Ashkenas 10 | Copyright (c) 2014-2015 Caoxingming 11 | 12 | Permission is hereby granted, free of charge, to any person 13 | obtaining a copy of this software and associated documentation 14 | files (the "Software"), to deal in the Software without 15 | restriction, including without limitation the rights to use, 16 | copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the 18 | Software is furnished to do so, subject to the following 19 | conditions: 20 | 21 | The above copyright notice and this permission notice shall be 22 | included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 26 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 28 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 29 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 31 | OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | var Module, binary, child_process, ext, findExtension, fork, loadFile, path, taiji, utils, _i, _len, _ref; 34 | 35 | child_process = require('child_process'); 36 | 37 | path = require('path'); 38 | 39 | taiji = require('./taiji'); 40 | 41 | utils = require('./utils'); 42 | 43 | loadFile = function(module, filename) { 44 | var answer; 45 | answer = taiji._compileFile(filename, false); 46 | return module._compile(answer, filename); 47 | }; 48 | 49 | if (require.extensions) { 50 | _ref = taiji.FILE_EXTENSIONS; 51 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 52 | ext = _ref[_i]; 53 | require.extensions[ext] = loadFile; 54 | } 55 | Module = require('module'); 56 | findExtension = function(filename) { 57 | var curExtension, extensions; 58 | extensions = path.basename(filename).split('.'); 59 | if (extensions[0] === '') { 60 | extensions.shift(); 61 | } 62 | while (extensions.shift()) { 63 | curExtension = '.' + extensions.join('.'); 64 | if (Module._extensions[curExtension]) { 65 | return curExtension; 66 | } 67 | } 68 | return '.js'; 69 | }; 70 | Module.prototype.load = function(filename) { 71 | var extension; 72 | this.filename = filename; 73 | this.paths = Module._nodeModulePaths(path.dirname(filename)); 74 | extension = findExtension(filename); 75 | Module._extensions[extension](this, filename); 76 | return this.loaded = true; 77 | }; 78 | } 79 | 80 | if (child_process) { 81 | fork = child_process.fork; 82 | binary = require.resolve('../bin/taiji'); 83 | child_process.fork = function(path, args, options) { 84 | if (utils.isTaiji(path)) { 85 | if (!Array.isArray(args)) { 86 | options = args || {}; 87 | args = []; 88 | } 89 | args = [path].concat(args); 90 | path = binary; 91 | } 92 | return fork(path, args, options); 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /lib/taiji.js: -------------------------------------------------------------------------------- 1 | var Environment, Parser, TaijiModule, addPrelude, begin, compile, compileExp, compileExpNoOptimize, compileInteractive, entity, ext, extend, formatTaijiJson, initEnv, metaCompile, metaConvert, optimizeExp, rootModule, textizerOptions, transformExp, _base, _i, _len, _ref, _ref1, _ref2; 2 | 3 | exports.VERSION = '0.1.0'; 4 | 5 | _ref = require('./utils'), extend = _ref.extend, begin = _ref.begin, formatTaijiJson = _ref.formatTaijiJson, addPrelude = _ref.addPrelude; 6 | 7 | TaijiModule = require('./module'); 8 | 9 | Parser = require('./parser').Parser; 10 | 11 | entity = require('./parser/base').entity; 12 | 13 | exports.Parser = Parser; 14 | 15 | _ref1 = require('./compiler'), Environment = _ref1.Environment, metaConvert = _ref1.metaConvert, transformExp = _ref1.transformExp, optimizeExp = _ref1.optimizeExp, compileExp = _ref1.compileExp, metaCompile = _ref1.metaCompile, compileExpNoOptimize = _ref1.compileExpNoOptimize; 16 | 17 | exports.Environment = Environment; 18 | 19 | exports.compileExp = compileExp; 20 | 21 | exports.builtins = extend({}, require('./builtins/core'), require('./builtins/js')); 22 | 23 | exports.textizerOptions = textizerOptions = { 24 | indentWidth: 2, 25 | lineLength: 80 26 | }; 27 | 28 | exports.rootModule = rootModule = new TaijiModule(__filename, null); 29 | 30 | exports.initEnv = initEnv = function(builtins, taijiModule, options) { 31 | var env; 32 | options = extend(options, textizerOptions); 33 | env = new Environment(extend({}, builtins), null, new Parser, taijiModule, {}, options); 34 | env.parser = new Parser; 35 | return env; 36 | }; 37 | 38 | exports.parse = function(code, taijiModule, builtins, options) { 39 | var env, exp, parser; 40 | env = initEnv(builtins, taijiModule, options); 41 | parser = env.parser; 42 | exp = parser.parse(code, parser.module, 0, env); 43 | return formatTaijiJson(entity(exp.body), 0, 0, false, 2, 70); 44 | }; 45 | 46 | exports.convert = function(code, taijiModule, builtins, options) { 47 | var env, exp, parser; 48 | env = initEnv(builtins, taijiModule, options); 49 | parser = env.parser; 50 | exp = parser.parse(code, parser.module, 0, env); 51 | exp = metaConvert(addPrelude(parser, exp.body), env); 52 | return formatTaijiJson(entity(exp), 0, 0, false, 2, 70); 53 | }; 54 | 55 | exports.transform = function(code, taijiModule, builtins, options) { 56 | var env, exp, parser; 57 | env = initEnv(builtins, taijiModule, options); 58 | parser = env.parser; 59 | exp = parser.parse(code, parser.module, 0, env); 60 | exp = transformExp(addPrelude(parser, exp.body), env); 61 | return formatTaijiJson(entity(exp), 0, 0, false, 2, 70); 62 | }; 63 | 64 | exports.optimize = function(code, taijiModule, builtins, options) { 65 | var env, exp, parser; 66 | env = initEnv(builtins, taijiModule, options); 67 | parser = env.parser; 68 | exp = parser.parse(code, parser.module, 0, env); 69 | exp = optimizeExp(addPrelude(parser, exp.body), env); 70 | return formatTaijiJson(entity(exp), 0, 0, false, 2, 70); 71 | }; 72 | 73 | exports.compileInteractive = compileInteractive = function(code, taijiModule, builtins, options) { 74 | var env, exp, objCode, parser; 75 | env = initEnv(builtins, taijiModule, options); 76 | parser = env.parser; 77 | exp = parser.parse(code, parser.moduleBody, 0, env); 78 | return objCode = compileExp(exp, env); 79 | }; 80 | 81 | exports.metaCompile = function(code, taijiModule, builtins, options) { 82 | var env, exp, objCode, parser; 83 | env = initEnv(builtins, taijiModule, options); 84 | parser = env.parser; 85 | exp = parser.parse(code, parser.module, 0, env); 86 | return objCode = metaCompile(addPrelude(parser, exp.body), [], env); 87 | }; 88 | 89 | exports.compile = compile = function(code, taijiModule, builtins, options) { 90 | var env, exp, objCode, parser; 91 | env = initEnv(builtins, taijiModule, options); 92 | parser = env.parser; 93 | exp = parser.parse(code, parser.module, 0, env); 94 | return objCode = compileExp(addPrelude(parser, exp.body), env); 95 | }; 96 | 97 | exports.compileNoOptimize = function(code, taijiModule, builtins, options) { 98 | var env, exp, objCode, parser; 99 | env = initEnv(builtins, taijiModule, options); 100 | parser = env.parser; 101 | exp = parser.parse(code, parser.module, 0, env); 102 | return objCode = compileExpNoOptimize(addPrelude(parser, exp.body), env); 103 | }; 104 | 105 | exports["eval"] = function(code, taijiModule, builtins, options) { 106 | var x; 107 | x = compile(code, taijiModule, builtins, options); 108 | return eval(x); 109 | }; 110 | 111 | exports.FILE_EXTENSIONS = ['.taiji', '.tj']; 112 | 113 | exports.register = function() { 114 | return require('./register'); 115 | }; 116 | 117 | if (require.extensions) { 118 | _ref2 = exports.FILE_EXTENSIONS; 119 | for (_i = 0, _len = _ref2.length; _i < _len; _i++) { 120 | ext = _ref2[_i]; 121 | if ((_base = require.extensions)[ext] == null) { 122 | _base[ext] = function() { 123 | throw new Error("Use taiji.register() or require the taiji/register module to require " + ext + " files."); 124 | }; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taiji", 3 | "description": "taiji language", 4 | "keywords": ["javascript", "language", "taijilang", "compiler", "taiji"], 5 | "author": "曹星明(Caoxingming, or Taiji Zhenren, simeon.chaos@gmail.com)", 6 | "version": "0.1.0", 7 | "licenses": [{ 8 | "type": "MIT", 9 | "url": "https://raw.github.com/taijilang/taijilang/master/LICENSE" 10 | }], 11 | "engines": { 12 | "node": ">=0.8.0" 13 | }, 14 | "directories" : { 15 | "lib" : "./lib", 16 | "bin": "./bin", 17 | "doc": "./doc", 18 | "example": "./samples" 19 | }, 20 | "main" : "./lib/taiji.js", 21 | "bin": { 22 | "taiji": "./bin/taiji" 23 | }, 24 | "homepage": "https://github.com/taijiweb/taijilang", 25 | "bugs": "https://github.com/taijiweb/taijilang/issues", 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/taijiweb/taijilang.git" 29 | }, 30 | "dependencies": { 31 | "mkdirp": "~0.3.5" 32 | }, 33 | "devDependencies": { 34 | "coffee-script": "1.7.1", 35 | "mocha": "~1.17.0", 36 | "chai": "~1.8.1", 37 | "shelljs": "~0.3.0", 38 | "gulp": "^3.6.2", 39 | "gulp-util": "^2.2.19", 40 | "gulp-coffee": "~1.4.1", 41 | "gulp-mocha": "~0.3.0", 42 | "gulp-changed": "~0.2.1", 43 | "gulp-cached": "0.0.2", 44 | "gulp-plumber": "~0.5.6", 45 | "gulp-mocha": "~0.4.1", 46 | "gulp-shell": "~0.2.4", 47 | "gulp-rename": "~0.2.2", 48 | "gulp-clean": "~0.2.4", 49 | "run-sequence": "~0.3.6" 50 | }, 51 | "scripts": { 52 | }, 53 | "preferGlobal": true 54 | } 55 | -------------------------------------------------------------------------------- /register.js: -------------------------------------------------------------------------------- 1 | require('./lib/register'); 2 | -------------------------------------------------------------------------------- /repl.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/repl'); 2 | -------------------------------------------------------------------------------- /roadmap.md: -------------------------------------------------------------------------------- 1 | ### roadmap of the future 2 | * bootstrap: implememnt taijilang by taijilang itself 3 | 4 | * features 5 | * taiji to other things: css, html 6 | * compile .tj or .tj.json to .js( diffenent from running .tj and generate a .js) 7 | * sourcemap 8 | 9 | * document 10 | below is chinese(zh-cn) 11 | * 语言规范:基本概念 (doc/zh-cn/太极语言规范.md) 12 | * 教程: 安装 (doc/zh-cn/太极语言教程.md) -------------------------------------------------------------------------------- /samples/block.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | a = 1 4 | block! a = 1 -------------------------------------------------------------------------------- /samples/blockcomment.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | 1 4 | /. this is a block comment 5 | any line 6 | indented 7 | is a part of the block comment 8 | no end tag is needed for a block comment 9 | 10 | print 'something' // this is code line 11 | -------------------------------------------------------------------------------- /samples/bootstrap/readme.md: -------------------------------------------------------------------------------- 1 | The files in this folder will become the bootstrap implementation of taijilang in the future. 2 | But at the moment they not finished yet. 3 | They are temporally put here to demonstrate the compilation of taijilang. -------------------------------------------------------------------------------- /samples/bootstrap/repl.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | This program is used to demonstrate and test compilation, not a part of bootstrap of taijilang. 4 | 5 | It is not tested yet. 6 | 7 | A very simple REPL written in taijilang 8 | 9 | extern! str taiji 10 | 11 | require "./require" 12 | readline = require "readline" 13 | tj = require "../lib/taijilang" 14 | prefix = "tj> " 15 | 16 | exports.runrepl = -> 17 | rl = readline.createInterface process.stdin process.stdout 18 | rl.on 'line' (line) -> 19 | line1 = tj._compile line 20 | console.log: eval line1 21 | (err) -> console.log err 22 | rl.setPrompt prefix prefix.length 23 | rl.prompt() 24 | rl.on 'close' -> 25 | console.log "Bye!" 26 | process.exit 0 27 | console.log "$prefix taijilang repl v$taiji.version" 28 | rl.setPrompt prefix prefix.length 29 | rl.prompt() 30 | 31 | -------------------------------------------------------------------------------- /samples/bootstrap/require.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this program is used to demonstrate and test compilation, not a part of bootstrap of taijilang. 4 | 5 | fs = require "fs" 6 | taiji = require "../lib/taiji" 7 | 8 | require.extensions[".tj"] = (module, filename) -> 9 | code = fs.readFileSync filename "utf8" 10 | module._compile: taiji._compile code filename, filename 11 | 12 | require "../src/macros" -------------------------------------------------------------------------------- /samples/bootstrap/taijilang.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | This program is used to demonstrate and test compilation, not a part of bootstrap of taijilang. 4 | It is not tested yet. 5 | 6 | require "./require" 7 | fs = require "fs" 8 | tj = require "./tj" 9 | repl = require "./repl" 10 | isValidFlag = /-h\b|-r\b|-v\b|-b\b/ 11 | error = (err) -> 12 | console.error err.message 13 | process.exit 1 14 | 15 | help_str = ''' 16 | Usage: taiji [-h] [-r] [-v] [-b] [] [] 17 | 18 | Also compile stdin to stdout 19 | eg. $ echo 'console.log \"hello\"' | lispy 20 | 21 | Run REPL 22 | -h Show this help 23 | -r Compile and run 24 | -v Show Version 25 | -b Create browser-bundle.js in same folder. 26 | Input file to compile 27 | Output JS file. If not given 28 | will be with .js extension\n''' 29 | 30 | // We use maybe monad to carry out each step, so that we can 31 | // halt the operation anytime in between if needed. 32 | 33 | extern! doMonad maybeMonad 34 | doMonad maybeMonad 35 | 36 | // Start maybe Monad bindings 37 | // First step get args without the first two node and lispy. 38 | args = process.argv.slice 2 39 | 40 | // get the first arg 41 | arg1 = args.shift() 42 | 43 | // when no args do stdin -> stdout compile or run repl and return null to 44 | // halt operations. 45 | extern! noargs \when isUndefined setTimeout 46 | noargs 47 | \when isUndefined(arg1) 48 | input = process.stdin 49 | output = process.stdout 50 | input.resume() 51 | input.setEncoding "utf8" 52 | source = "" 53 | // Accumulate text form input until it ends. 54 | input.on "data" (chunck) -> source += chunck.toString() 55 | // Once input ends try to compile & write to output. 56 | input.on "end" -> 57 | /. try 58 | output.write tj._compile source process.cwd 59 | error() 60 | catch then print 'ok' 61 | input.on "error" error 62 | output.on "error" error 63 | setTimeout -> 64 | if input.bytesRead = 0 then 65 | begin! 66 | input.removeAllListeners "data" 67 | repl.runrepl 20 68 | null 69 | 70 | // If arg1 = flag verify valid flag and halt 71 | // otherwise set arg1 to next arg in args 72 | extern! flag Error run infile outfile unless 73 | flag 74 | \when "-"==arg1./0 75 | var flag = arg1 76 | arg1 = args.shift() 77 | if isValidFlag.test(flag) then 78 | flag 79 | error: new: Error "Error: Invalid flag "+flag 80 | 81 | run 82 | /.switch flag 83 | "-h": console.log help_str null 84 | "-v": console.log "Version "+tj.version null 85 | "-b": 86 | var bundle 87 | require.resolve "lispyscript/lib/browser-bundle.js" 88 | fs.createReadStream(bundle).pipe 89 | fs.createWriteStream "browser-bundle.js" 90 | null 91 | "-r": true 92 | 93 | 94 | // if infile undefined 95 | infile 96 | if arg1 then arg1 97 | else error: new: Error "Error: No Input file given" 98 | 99 | // set outfile args.shift. ! outfile set outfile to infile.js 100 | outfile 101 | begin! 102 | outfile = args.shift() 103 | unless outfile 104 | outfile = infile.replace /\.ls$/ ".js" 105 | if outfile==infile then 106 | error: new: Error: "Error: Input file must have extension '.tj'" 107 | outfile 108 | 109 | // compile infile to outfile. if not run return null. 110 | extern! js tryDo node 111 | js 112 | tryDo 113 | fs.writeFileSync outfile 114 | tj._compile 115 | fs.readFileSync infile "utf8" 116 | infile 117 | "utf8" 118 | if run then run() else null 119 | (err) -> 120 | error err 121 | null // end of maybe Monad bindings 122 | 123 | // we are here if -r true, so run it! 124 | -> 125 | require "child_process" 126 | node.spawn outfile() {stdio: "inherit"} -------------------------------------------------------------------------------- /samples/breakout/breakout.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | 4 | #wrapper { 5 | margin: 20px auto 0px auto; 6 | padding: 0; 7 | width: 450px; 8 | } 9 | 10 | #breakout { 11 | margin: 0; 12 | padding: 0; 13 | background: #ddd; 14 | } -------------------------------------------------------------------------------- /samples/breakout/breakout.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | the file is ported from lispyscript 4 | Thanks to [santoshrajan](https://github.com/santoshrajan), 5 | Taijilang get some ideas from [lispyscript](https://github.com/taijiweb/lispyscript). 6 | 7 | The breakout game written in Taijilang 8 | Open the html file in the same folder to try it. 9 | Requires canvas support in browser 10 | Based on javascript version here http://www.jsdares.com/ 11 | 12 | include! "browser.tj" 13 | 14 | canvas = null 15 | context = null 16 | bricksNumX = 7; bricksNumY = 5 17 | brickWidth = nul; brickHeight = 20 18 | brickMargin = 4 19 | paddleWidth = 80; paddleHeight = 12 20 | paddleX = 0 21 | ballX = ballY = ballVx = ballVy = 0 22 | 23 | bricks = arrayInit2d 5 7 null 24 | 25 | init = -> 26 | # @@varName is used to assign to variable in the outside scope 27 | @@paddleX = canvas.width/2 28 | @@ballX = 40 29 | @@ballY = 150 30 | @@ballVx = 7 31 | @@ballVy = 12 32 | each2d @@bricks = (val, i, j, arr) -> arr[i] = true 33 | 34 | clear = context.clearRect 0 0 canvas.width canvas.height 35 | 36 | circle = (x y) -> 37 | context.beginPath() 38 | context.arc x y 10 0 2*Math.PI 39 | context.fill() 40 | 41 | drawPaddle = -> 42 | /.in taijilang, space can change the precedence of the operator 43 | so the expression below is equal to 44 | x = paddleX - (paddleWidth / 2) 45 | the eyes love space. just believe your eyes. 46 | x = paddleX - paddleWidth/2 47 | y = canvas.height - paddleHeight 48 | context.fillRect x y paddleWidth paddleHeight 49 | 50 | drawBricks = -> 51 | each2d bricks (val x y arr) -> 52 | if val then 53 | xpos = x*brickWidth + brickMargin/2 54 | ypos = y*brickHeight + brickMargin/2 55 | width = brickWidth - brickMargin 56 | height = brickHeight - brickMargin 57 | context.fillRect xpos ypos width height 58 | 59 | hitHorizontal = -> 60 | if ballX<0 || ballX>canvas.width then @@ballVx-ballVx 61 | 62 | hitVertical = -> 63 | if ballY<0 then @@ballVy = -ballVy; true 64 | if ballY < brickHeight*bricksNumY 65 | bx = Math.floor ballX/brickWidth 66 | by = Math.floor ballY/brickHeight 67 | if bx>=0 && bx= canvas.height-paddleHeight 72 | paddleLeft = paddleX - paddleWidth/2 73 | paddleRight = paddleX + paddleWidth/2 74 | if ballX>=paddleLeft && ballX&&paddleRight then @@ballVy = -ballVy; true 75 | else init(); false 76 | else true 77 | 78 | tick = -> 79 | clear() 80 | drawPaddle() 81 | @@ballX += ballVx)) 82 | @@ballY += ballVy)) 83 | hitHorizontal() 84 | if hitVertical() then circle ballX ballY; drawBricks() 85 | else clear() 86 | 87 | window.onload = (event) -> 88 | @@canvas = $ "breakout" 89 | @@context = canvas.getContext "2d" 90 | @@brickWidth = canvas.width / bricksNumX 91 | $listener canvas "mousemove" paddleX = event.offsetX || event.pageX-canvas.offsetLeft 92 | init() 93 | window.setInterval tick 30 94 | -------------------------------------------------------------------------------- /samples/breakout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Breakout Game 5 | 6 | 7 | 8 |
9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/breakout/reamd.md: -------------------------------------------------------------------------------- 1 | the files in this folder is ported from lispyscript. 2 | These stuffs is just used to demonstrate some features and compiling process of taijilang, not as a logical correct sample application. 3 | Thanks to [santoshrajan](https://github.com/santoshrajan), Taijilang get some ideas from [lispyscript](https://github.com/taijiweb/lispyscript). -------------------------------------------------------------------------------- /samples/chatserver.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | A simple chatserver written in taijilang 4 | Connect to the server via telnet. 5 | $ telnet 6 | Any message typed in is broadcast to all other clients connected 7 | 8 | net = require "net" 9 | chatServer = net.createServer() 10 | port = 3000 11 | clientList = [] 12 | 13 | var each 14 | 15 | broadcast = (message, client) -> 16 | each clientList (currentClient) -> 17 | if currentClient<>client then 18 | currentClient.write "$client.name says $message" 19 | 20 | chatServer.on "connection" (client) -> 21 | client.name = "$client.remoteAddress : $client.remotePort" 22 | client.write "Hi $client.name \n" 23 | clientList.push client 24 | client.on "data" (data) -> broadcast data client 25 | // We dont want the server to crash while writing to a disconnected client. 26 | // The 'end' event listener is called if client disconnects. 27 | client.on "end" -> clientList.splice: clientList.indexOf client, 1 28 | 29 | chatServer.listen port 30 | -------------------------------------------------------------------------------- /samples/demo.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | var x, y; [x...y] 4 | [x..y] -------------------------------------------------------------------------------- /samples/democlass.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | //import! #\class from 'class.tj' 4 | include! 'class@.tj' 5 | 6 | a = 1 7 | 8 | class A 9 | ::a = 1 10 | a = 1 11 | 12 | class B extends A 13 | 14 | class C extends A :: = -> super 15 | 16 | class D extends A 17 | :: = -> super 18 | ::f = -> super 19 | 20 | class E extends A 21 | :: = -> super(1) 22 | ::f = -> super 23 | a = 1 24 | ::a = 2 25 | ::g = -> super 3 4 -------------------------------------------------------------------------------- /samples/ellipsis.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | // ellipsis parameter similar to coffeescript 4 | 5 | (x...)->x 6 | (x, y...)->x 7 | (x, y, z...)->x 8 | 9 | (x, y, z..., a)->x 10 | 11 | (x, y, z..., a)->x 12 | 13 | (x, y, z..., a, b)->x 14 | 15 | (z..., a, b)->z 16 | 17 | (x, y, z..., a, b, c, d, e)->z 18 | 19 | m = (x..., b) -> print x, print b 20 | 21 | m(1, 2, 3) 22 | 23 | // macro can have ellipsis parameters too. 24 | 25 | m #= (x..., b) -> ` [begin!: print ^&x, print ^b ] 26 | 27 | m#(1, 2, 3) 28 | 29 | var x, y, z, a, n, p, q 30 | 31 | [x, y..., z] = [1, 2, 3, 4] 32 | a = [1, 2, 3, 4] 33 | [x, y..., z] = a 34 | a = [1, 2, 3, 4, 5, 6] 35 | [x, y, z..., m] = a 36 | [x, y, z..., m, n] = a 37 | 38 | (a=1, x..., b=a, c={. .}) -> 1 -------------------------------------------------------------------------------- /samples/express_bootstrap.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this file is not tested yet. 4 | taijilang example using nodejs, expressjs and twitter bootstrap 5 | taijilang templates are written in taijilang! 6 | Html5 templates support all html5 tags 7 | 8 | // The express server 9 | 10 | express = require "express" 11 | app = express() // same as express() 12 | app.listen 3000 13 | app.use: express.static __dirname+"/public" 14 | 15 | // Include html5 template support 16 | 17 | include "html.tj" 18 | 19 | /.Base Page template common to all pages 20 | To which we pass arguments title, navBarLinks, bodyContent 21 | when we call the template 22 | 23 | template basePage [pageTitle navBarLinks bodyContent] 24 | html{lang:"en"} 25 | head 26 | title pageTitle 27 | link{href:'bootstrap/css/bootstrap.css', rel:'stylesheet'} 28 | style type:'text/css' 29 | "body{padding-top: 60px; }" 30 | link {href: 'bootstrap/css/bootstrap-responsive.css', rel:'stylesheet'} 31 | // Le HTML5 shim, for IE6-8 support of HTML5 elements 32 | '''''' 35 | body 36 | div{class: "navbar navbar-fixed-top"} 37 | div{class: "navbar-inner"} 38 | div{class:"container"} 39 | a{class:"btn btn-navbar", 40 | "data-toggle":"collapse", 41 | "data-target":".nav-collapse"} 42 | "" 43 | "" 44 | ""} 45 | a{class:"brand", href:"#"} "taijilang!" 46 | div {class:"nav-collapse"} 47 | navBarLinks //navBarLinks added here 48 | bodyContent // bodyContent added here 49 | script {src:"//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js",type:"text/javascript"} 50 | script {type:"text/javascript",src:"bootstrap/js/bootstrap.js"} 51 | 52 | // the navBarLinks template 53 | 54 | template navBarLinks [] 55 | ul{class:'nav'} 56 | li{class:'active'}: a{href:'#'} "Home" 57 | li: a{href:'/tryit'} "Try It" 58 | li: a{href:'/docs'} "Docs" 59 | 60 | // the bodyContent template 61 | 62 | template bodyContent [] 63 | div{class:'container'} 64 | div{class:'page-header'} 65 | h1 "taijilang" 66 | p "A javascript With Lispy Syntax And Macros!" 67 | div{class:'row'} 68 | div{class:'span6'} 69 | h2 "Overview") 70 | p "An inherent problem with Javascript is that it has no macro support, like other Lisp like languages. That's because macros manipulate the syntax tree while compiling. And this is next to impossible in a language like Javascript.")) 71 | div{class:'span6'} 72 | h2 "Installing" 73 | h4 "Install Using npm" 74 | pre "$ npm install -g lispyscript" 75 | 76 | // Send It! 77 | 78 | app.get "/" (req, res) -> res.send: basePage "taijilang" navBarLinks() bodyContent() 79 | -------------------------------------------------------------------------------- /samples/hello.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | print 'hello taiji' 4 | 5 | // print __taijiVersion 6 | 7 | // undefined? # 1 8 | 9 | "hello taiji" -------------------------------------------------------------------------------- /samples/import.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | //import! './hello.tj' 4 | import! './module1.tj' 5 | //import! a from './hello.tj' 6 | //import! a as a2 from './hello.tj' as html 7 | //import! a as A, #b from 'html.tj' as html #html2 8 | /. 9 | import! 'html.tj' 10 | import! 'html.tj' as html2 11 | 12 | import! #x as A from 'html.tj' as html3 13 | A() -------------------------------------------------------------------------------- /samples/include.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | a big bug in my idea 4 | include! will be deprecated!!! 5 | include! is dead, import! long alive! 6 | 7 | include! './module1.tj' -------------------------------------------------------------------------------- /samples/indent-then-else.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | // for extern variable, no var declaration is generated in the javascript. 4 | extern! add a b 5 | 6 | // the two code blocks below will generate the same javascript code 7 | if and 1 8 | add 2 3 9 | then print a // half dent after previous indent clause 10 | else print b 11 | 12 | if and 1 13 | add 2 3 14 | print a // half dent after previous indent clause, 'then' keyword is optional. 15 | else print b // "else" clause can be the same indent as "if" 16 | 17 | if (a > 1) 18 | then print a 19 | else print b 20 | 21 | // one key comment 22 | // a statement can become a comment block by one key "/" 23 | /if (a > 1) 24 | then print a 25 | else print b -------------------------------------------------------------------------------- /samples/let.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | let name="Jonh", email="john@example.com", tel= "555-555-5556" then 4 | console.log "name: $name email: $email tel:$tel" 5 | 6 | let a=1 then let a=2 then print a 7 | 8 | letrec! f = (x) -> if! x==1 1 f(x-1) then f(3) 9 | 10 | letloop! f = (x, acc) -> if! x==1 acc f(x-1, x+acc) then f(3, 0) 11 | 12 | letloop! f = (x) -> if! x==1 1 x+f(x-1) then f(3) 13 | 14 | letloop! 15 | odd = (x) -> if! x==0 0 even(x-1) 16 | even = (x) -> if! x==0 1 odd(x-1) 17 | then odd(3) 18 | 19 | letloop! gcd = (a, b) -> if! a>b gcd(a-b, b) {if! b>a gcd(a, b-a) a} then gcd 9 12 -------------------------------------------------------------------------------- /samples/loop.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | while! 1 {if 1 then console.log 1 else console.log 2} 4 | while! 2 if 1 then console.log 1 else console.log 2 5 | while! 2 if! 1 console.log(1) console.log(2) 6 | while! 3 7 | if 1 then console.log 1 else console.log 2 8 | -------------------------------------------------------------------------------- /samples/macros.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | closure #= (closureVars..., fn) -> `{(^&closureVars) -> ^fn}(^&closureVars) 4 | 5 | extern! x y a 6 | closure#(x, y, {-> x y}) 7 | closure # x, y -> 8 | print x y 9 | 10 | \do #= (body..., clause) => 11 | if clause[0]=='where' then 12 | `{let ^&(clause.slice(1)) then ^&body} 13 | else if clause[0]=='when' then 14 | `{doWhile! ^clause[1] ^&body} 15 | else if clause[0]=='until' then 16 | `{doWhile! not(^clause[1]) ^&body} 17 | 18 | //do 1 19 | // now the code below becomes valid: 20 | do 21 | print a 22 | print b 23 | where a=1, b=2 24 | i = 0; do print i++ until i==10 25 | 26 | do print a; print b where a=1, b=2 27 | do print a where a=1, b=2 28 | do print a where a=1 29 | 30 | do a when a==1 31 | do a until a==1 32 | 33 | {-> ~(1+2)}() -------------------------------------------------------------------------------- /samples/meta.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | array? #= (obj) -> ` (Object::toString.call(^obj) == '[object Array]') 4 | # {array? # 1} 5 | 6 | /* 7 | undefined? #= (obj) -> `((^obj)==undefined) 8 | # -> array? # [] 9 | a #= 1; b #= 0 10 | undefined? # 1 11 | 12 | y = 1 13 | f #= (x) -> `((^x)>=y) 14 | 15 | f#(1) 16 | 17 | # {undefined? a} 18 | # {undefined? # 1} 19 | 20 | # if a then console.log 1 else console.log 2 21 | # if b then console.log 1 else console.log 2 22 | */ -------------------------------------------------------------------------------- /samples/module1.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | 1 4 | #/ {var a} 5 | export! a 6 | export! #a, #/a, b = 1 -------------------------------------------------------------------------------- /samples/nodeserver.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | http = require "http" 4 | server = 5 | http.createServer (request, response) -> 6 | response.writeHead 200 {'Content-Type': 'text/plain'} 7 | response.end "Hello World\n" 8 | server.listen 3000 "127.0.0.1" 9 | console.log "Server running at http://127.0.0.1:3000/" 10 | -------------------------------------------------------------------------------- /samples/sample.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | 1 4 | 5 | // this is a line comment 6 | 7 | // line comment can lead a code block 8 | 2 9 | // multi level indent line comment block 10 | 3 11 | 12 | if (2 > 1) then 2 13 | if 1 then console.log 1 else console.log 2 14 | 15 | print 3+4 16 | // spaces affect the priority of operator 17 | print (3+4 * 5+6) // the parentheses is necessary for operator expression 18 | // so the above is equal to the below: 19 | print ((3 + 4) * (5 + 6)) 20 | 21 | var a=1, b=2, c=3, x=4, y=5, z=6 22 | begin! 1 2 23 | 24 | // space can change the priority of operator 25 | // expression in different lines is computed from up to down 26 | // but indented expression is like in a parenthesis 27 | (3+5*5 * 6+7 * 8+9 * a=1 28 | + 3+5+6 29 | * 7 + 8 + 9 30 | + 5*6 31 | + 7*9) 32 | x=(1 33 | +2*3 34 | +4*5 35 | +7*8 36 | +9/9) 37 | 38 | a.!=1 // a! can be a taiji language identifier, so we should separate a and != by "." 39 | // because ! can not be used as first character, so a!=1 equal to a != 1 now. 40 | // a<>1 // or we can use <> instead. 41 | // a.!==1; a<*>1 // for the same reason as the above 42 | y+.!1 // y+!1 will be parsed as [+! y 1], so we separate + and ! by "." 43 | y+.!x 44 | y+.!!1 // !!x equal to !(!x) or !.!x 45 | x+.!!y 46 | 47 | // ~ is the same as the lisp quote "'" 48 | ~ print 1 49 | 50 | // ":" lead a sequence of clauses. 51 | print : and 1 2 // this a line tail comment 52 | print: and 1 2, or 3 4 53 | 54 | /. this is a block comment 55 | any line 56 | indented 57 | is a part of the block comment 58 | no end tag is needed for a block comment 59 | // the all of above is one single block comment, and this line is a line comment 60 | 61 | // line comment can lead a indented block 62 | console.log : and 1 2 63 | console.log: and 1 2 64 | // indent again 65 | let a=[\ 1 \] then a[1] 66 | let a=[ 1 ] then a[1] 67 | 68 | => @a; @, @x([]+@), -> @a; @, @x([]+@) 69 | 70 | for x in [ 1, 2 ] then print x -------------------------------------------------------------------------------- /samples/sample2.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | if (a > 1) html : head : title : # tai ji; body : div : p : # something from taiji 4 | 5 | if (a > 1) 6 | html : head : title "tai ji" 7 | "" 8 | 9 | if (a > 1) : if (b>1) : if (c>1) : print c 10 | else: print c 11 | else: print b 12 | else: print a 13 | 14 | html : head : tile # taiji 15 | link '1.css' 16 | script '1.js' 17 | body 18 | div : 19 | adf 20 | dsfa 21 | asdfj;l 22 | 23 | 24 | switch a 25 | case: 1: sdaf 26 | case: 2: dsa 27 | default: dsaf 28 | 29 | // the code below generate the same internal representation as the above. 30 | switch a 31 | case: 1: sdaf 32 | case: 2: adfs 33 | default: dsafj 34 | 35 | -------------------------------------------------------------------------------- /samples/sequence.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | sequenced callback example 3 | No need for nested callbacks. Just write your callbacks in a sequence and pass "(next)" as 4 | your callback, which will set the next function in the sequence as your callback. 5 | This example is a simple node server that will serve static plain text file to the browser. 6 | 7 | fs = require "fs" 8 | http = require "http" 9 | 10 | requestHandler = sequence (request, response) -> 11 | filename = if request.url=="/" then "index.html" else request.url.substr 1 12 | response.setHeader "Content-Type" "text/html" 13 | -> fs.exists filename next 14 | (exists) -> if exists 15 | then fs.readFile filename "utf8" next 16 | else response.end "File Not Found" 17 | (err, data) -> 18 | if err then response.end "Internal Server Error" 19 | else response.end data 20 | 21 | server = http.createServer requestHandler 22 | server.listen 3000 "127.0.0.1" 23 | console.log "Server running at http://127.0.0.1:3000/" 24 | 25 | 26 | /. A sequence expression creates a function. The arguments are 27 | 1. The name for the function 28 | 2. The parameters definition for the function 29 | 3. A block of expressions to initialize the function. 30 | 4. The rest are a sequence of functions to be called in order. 31 | The sequence functions are defined in the scope of the sequence. 32 | All parameters and initialised variables are visible to all the sequence functions. 33 | Also visible to all the sequence functions is a function called next. 34 | next returns the next function in the sequence. 35 | 36 | In the example above we create a sequence function called requestHandler and set it as the request callback for the node server. 37 | In the initialization block we create a var called filename and set it to the requested file. 38 | We also set the response content type. 39 | There are three sequence functions and the first one ia called automatically when the request handler function is called. 40 | It in turn calls fs.exists with the filename and and sets the callback to "(next)". 41 | Which in this case is the second function in the sequence. 42 | The second function is the callback for the first, and it in turn calls fs.readFil and passes the thirst function (next) as the callback. 43 | Since the third function (callback for the second) does not call (next) the sequence ends there. 44 | 45 | -------------------------------------------------------------------------------- /samples/snippets.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | include! 'types@.tj' 4 | // Some example code snippets 5 | 6 | print 1 2 7 | 8 | //undefined? #= (obj) -> `(typeof( ^obj )==undefined) 9 | //object? #= (obj) -> `( typeof( ^obj ) == 'object' ) 10 | //array? #= (obj) -> `( Object.prototype.toString.call( ^obj ) === '[object Array]' ) 11 | 12 | if undefined? # window then 13 | console.log "Not Running on browser" 14 | else console.log "Running on browser" 15 | 16 | arr = ~[1 2 3 4 5] 17 | console.log arr[2] 18 | if! 1!=2 [console.log "Nos are not equal"] 19 | 20 | if object? # console then 21 | console.log "console is an object" 22 | else console.log "console is not an object" 23 | 24 | if object? # console 25 | then console.log "console is an object" 26 | else console.log "console is not an object" 27 | 28 | if object? # console 29 | then console.log "console is an object" 30 | else console.log "console is not an object" 31 | 32 | if object? # console then if arr 33 | then console.log "console is an object" 34 | else console.log "console is not an object" 35 | 36 | if object? # console then if arr then if arr!=1 37 | then console.log "console is an object" 38 | else console.log "console is not an object" 39 | else console.log "console is not an object" 40 | 41 | if array? # console then 42 | console.log "console is an array" 43 | else console.log "console is not an array" 44 | 45 | _ = require 'underscore' 46 | 47 | Array.prototype.forEach.call ~[1 2 3] (elem, i, list) -> console.log elem 48 | Array.prototype.forEach.call [1 2 3] (elem, i, list) -> console.log elem 49 | 50 | /. var 51 | 52 | 53 | macro let [args vals rest...] 54 | [function ~args ~rest...] ~@vals 55 | 56 | do 57 | console.log "testing do" 58 | console.log "test again" 59 | 60 | var link 61 | template [data] 62 | "
  • " data.href "
  • \n" 63 | 64 | 65 | template page [title links] 66 | 67 | " 68 | 69 | 70 | " title " 71 | 72 | 73 | 78 | 79 | ") 80 | 81 | console.log 82 | page "My Home Page" 83 | [{href:"/about", text:"About"}, 84 | {href:"/products", text:"Products"}, 85 | {href:"/contact", text:"Contact"}] 86 | 87 | -------------------------------------------------------------------------------- /samples/square-macro.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | // Some example code snippets 4 | 5 | square = (n) -> n*n 6 | console.log: square 10 7 | 8 | square! #= (n) -> ` ( ^n * ^n ) 9 | console.log: square! # 10 10 | x = 1 11 | square! # x 12 | 13 | // The code above works fine. Now consider the code below 14 | // The example below shows the dangers of using a macro 15 | i = 2 16 | console.log: square! # i++ 17 | // Oops you got 6! An embarrassing square of a no. Thats because the macro 18 | // expanded to (i++ * i++) which is multiplying 2 and three! 19 | 20 | // the version below is safe with parameter which have side effects 21 | square2! #= (n) -> ` { let x = ^n then (x * x) } 22 | console.log: square2! # (i++) 23 | console.log: square2!#(i++) 24 | -------------------------------------------------------------------------------- /samples/twitter.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | A Twitter like web app 4 | Requires express js 5 | 6 | express = require "express" 7 | app = express() 8 | app.listen 3000 9 | 10 | /.Templates we will be using Base template common to all pages. 11 | Note that strings in taijilang can be multiline. 12 | 13 | template base (title, header, body) 14 | " 15 | 16 | 17 | " title " 18 | 19 | 20 |

    " header "

    " 21 | body 22 | " 23 | " 24 | 25 | // index page template. (the body part) 26 | 27 | template index [] 28 | "

    Enter Tweet

    29 |
    30 | 31 | 32 |
    33 |

    All Tweets

    " 34 | template-repeat tweets "
    " elem "
    " 35 | 36 | tweets = [] 37 | 38 | app.get "/", (req, res) -> res.send = base "Our Own Twitter" "Our Own Twitter" [index] 39 | 40 | app.post "/send" express.bodyParser() (req, res) -> 41 | if req.body&&req.body.tweet then 42 | tweets.push req.body.tweet 43 | res.redirect "/" 44 | res.send {status: "nok", message: "No tweet Received"} 45 | 46 | app.get "/tweets" (req, res) -> res.send tweets 47 | 48 | -------------------------------------------------------------------------------- /src/bin/taiji.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | path = require('path') 3 | fs = require('fs') 4 | 5 | lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib') 6 | require(lib + '/command').run() -------------------------------------------------------------------------------- /src/browser.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/browser.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | this file is not tested in taiji still. 6 | ### 7 | ### 8 | Copyright (c) 2009-2014 Jeremy Ashkenas 9 | Copyright (c) 2014-2015 Caoxingming 10 | 11 | Permission is hereby granted, free of charge, to any person 12 | obtaining a copy of this software and associated documentation 13 | files (the "Software"), to deal in the Software without 14 | restriction, including without limitation the rights to use, 15 | copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the 17 | Software is furnished to do so, subject to the following 18 | conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 25 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 27 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 28 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 | OTHER DEALINGS IN THE SOFTWARE. 31 | ### 32 | 33 | # This **Browser** compatibility layer extends core taiji functions 34 | # to make things work smoothly when compiling code directly in the browser. 35 | # We add support for loading remote Coffee scripts via **XHR**, and 36 | # `text/taiji` script tags, source maps via data-URLs, and so on. 37 | 38 | taiji = require './taiji' 39 | taiji.require = require 40 | compile = taiji.compile 41 | 42 | # Use standard JavaScript `eval` to eval code. 43 | taiji.eval = (code, options = {}) -> 44 | options.bare ?= true 45 | eval compile code, options 46 | 47 | # Running code does not provide access to this scope. 48 | taiji.run = (code, options = {}) -> 49 | options.bare = true 50 | options.shiftLine = true 51 | Function(compile code, options)() 52 | 53 | # If we're not in a browser environment, we're finished with the public API. 54 | return unless window? 55 | 56 | # Include source maps where possible. If we've got a base64 encoder, a 57 | # JSON serializer, and tools for escaping unicode characters, we're good to go. 58 | # Ported from https://developer.mozilla.org/en-US/docs/DOM/window.btoa 59 | if btoa? and JSON? and unescape? and encodeURIComponent? 60 | compile = (code, options = {}) -> 61 | options.sourceMap = true 62 | options.inline = true 63 | {js, v3SourceMap} = taiji.compile code, options 64 | "#{js}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent v3SourceMap}\n//# sourceURL=taiji" 65 | 66 | # Load a remote script from the current domain via XHR. 67 | taiji.load = (url, callback, options = {}, hold = false) -> 68 | options.sourceFiles = [url] 69 | xhr = if window.ActiveXObject 70 | new window.ActiveXObject('Microsoft.XMLHTTP') 71 | else 72 | new window.XMLHttpRequest() 73 | xhr.open 'GET', url, true 74 | xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr 75 | xhr.onreadystatechange = -> 76 | if xhr.readyState is 4 77 | if xhr.status in [0, 200] 78 | param = [xhr.responseText, options] 79 | taiji.run param... unless hold 80 | else 81 | throw new Error "Could not load #{url}" 82 | callback param if callback 83 | xhr.send null 84 | 85 | # Activate taiji in the browser by having it compile and evaluate all script tags with a content-type of `text/taiji`. 86 | # This happens on page load. 87 | runScripts = -> 88 | scripts = window.document.getElementsByTagName 'script' 89 | taijitypes = ['text/taiji'] 90 | taijis = (s for s in scripts when s.type in taijitypes) 91 | index = 0 92 | 93 | execute = -> 94 | param = taijis[index] 95 | if param instanceof Array 96 | taiji.run param... 97 | index++ 98 | execute() 99 | 100 | for script, i in taijis 101 | do (script, i) -> 102 | options = literate: script.type is taijitypes[1] 103 | if script.src then taiji.load script.src,((param) -> taijis[i] = param; execute()), options, true 104 | else 105 | options.sourceFiles = ['embedded'] 106 | taijis[i] = [script.innerHTML, options] 107 | 108 | execute() 109 | 110 | # Listen for window load, both in decent browsers and in IE. 111 | if window.addEventListener then window.addEventListener 'DOMContentLoaded', runScripts, no 112 | else window.attachEvent 'onload', runScripts 113 | -------------------------------------------------------------------------------- /src/compiler/analyze.coffee: -------------------------------------------------------------------------------- 1 | {str, entity, isValue, isArray, extend, error, wrapInfo1} = require '../utils' 2 | 3 | truth = (exp, env) -> 4 | exp = entity(exp) 5 | if not exp? then return 2-!!exp 6 | if typeof exp == 'string' 7 | if exp[0]=='"' then return 2-!!exp[1...exp.length-1] 8 | else return 9 | else if exp.push then return 10 | return 2-!!exp 11 | 12 | setValue = (x) -> 13 | if x==undefined then undefinedExp 14 | else if typeof x == 'string' then '"'+x+'"' 15 | else x 16 | 17 | #todo: maybe this utility can be deprecated, because we can eval(tocode(exp)) 18 | getValue = (x) -> entity(x) 19 | 20 | analyzeDefinition = (exp, env) -> 21 | 22 | analyzeFnMap = 23 | '=': (exp, env) -> 24 | left = exp[1] 25 | eLeft = entity(left) 26 | if typeof eLeft=='string' 27 | # while optimizing, replace the reference of left with value unconditionally. 28 | # is this necessary to do this while analyzing? 29 | if left.const and isAtomicValue(exp[2]) then exp.removable = true 30 | else 31 | info = env.info(left) 32 | if not info then env.optimizeInfoMap[left] = info = {} 33 | info.assign = exp 34 | exp.refCount = 0 35 | else analyze(left, env); analyze(exp[2], env) 36 | 37 | 'var': (exp, env) -> 38 | v = entity(exp[1]) 39 | env.optimizeInfoMap[v] = info = {} 40 | info.assign = undefined 41 | info.decl = exp 42 | 43 | # because now is after transforming, so prefix! is only object language prefix operator. 44 | 'prefix!': (exp, env) -> analyze(exp[2], env) 45 | 'suffix!': (exp, env) -> analyze(exp[2], env) 46 | 'binary!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 47 | 'augmentAssign!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 48 | 'attribute!': (exp, env) -> analyze(exp[1], env) 49 | 'index!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 50 | 'augmentAssign!': (exp, env) -> analyze(exp[2], env); analyze(exp[3], env) 51 | 'list!': (exp, env) -> for e in exp[1...] then analyze(e, env) 52 | 'begin!': (exp, env) -> for e in exp[1...] then analyze(e, env) 53 | 54 | 'debugger': (exp, env) -> 55 | 'break': (exp, env) -> 56 | 'continue': (exp, env) -> 57 | 'return': (exp, env) -> analyze(exp[1], env) 58 | 'quote!': (exp, env) -> 59 | 'regexp!': (exp, env) -> 60 | 'noop!': (exp, env) -> 61 | 'jsvar!': (exp, env) -> # analyze(exp[1], env) # do not change reference count for jsvar! 62 | 'label!': (exp, env) -> analyze(exp[1], env) 63 | 'new': (exp, env) -> analyze(exp[1], env) 64 | 'hash!': (exp, env) -> analyze(exp[1], env) 65 | 'hashitem!': (exp, env) -> analyze(exp[2], env) 66 | 'call!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 67 | 68 | 'if': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env); analyze(exp[3], env) 69 | 'while': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env) 70 | 'doWhile!': (exp, env) -> analyze(exp[2], env); analyze(exp[1], env) 71 | 'forIn!': (exp, env) -> 72 | # [forIn! loopVariable range body] 73 | # loopVariable should not be treated as variable reference, so exp[1] is skipped 74 | analyze(exp[2], env); analyze(exp[3], env) 75 | 'cFor!': (exp, env) -> analyze(exp[1], env); analyze(exp[2], env); analyze(exp[3], env); analyze(exp[4], env) 76 | 'try!': (exp, env) -> 77 | # [try test catchVariable catchBody finallyBody] 78 | # catchVariable should not be treated as catchVariable reference, so exp[2] is skipped 79 | analyze(exp[1], env); analyze(exp[3], env); analyze(exp[4], env) 80 | 'switch!': (exp, env) -> 81 | # [switch test cases body] 82 | analyze(exp[1], env); analyze(exp[1], env); analyze(exp[1], env) 83 | 84 | # ->, =>, |->, |=> have been transformed to function! 85 | #[function! [params...] body] 86 | 'function': (exp, env) -> 87 | # use the env which is own to [function! ...] 88 | env = exp.env; env.optimizeInfoMap = {} 89 | for e in exp[1] then env.optimizeInfoMap[entity(e)] = info = {}; info.assign = [] 90 | analyze(exp[2], exp.env) 91 | 92 | 'letloop': (exp, env) -> 93 | #[params, bindings, body] 94 | env = exp.env; env.optimizeInfoMap = {} 95 | bindings = exp[2] 96 | for b in bindings then transform(b[1], env) 97 | analyze(exp[3], env) 98 | 99 | exports.analyze = analyze = (exp, env) -> 100 | e = entity exp 101 | if not e then return 102 | if typeof e == 'string' 103 | if e[0]=='"' then return 104 | info = env.info(e) 105 | if info and info.assign then info.assign.refCount++ 106 | if info and info.decl then info.decl.refCount++ 107 | if not exp.push then return 108 | if exp.analyzed then return 109 | if fn=analyzeFnMap[exp[0]] 110 | result = fn(exp, env) 111 | if result==exp then return result 112 | if result and result.push then result.analyzed = true 113 | result = wrapInfo1 result, exp 114 | result.env = env 115 | else 116 | for e in exp then analyze(e, env) 117 | exp.analyzed = true -------------------------------------------------------------------------------- /src/compiler/env.coffee: -------------------------------------------------------------------------------- 1 | {extend, javascriptKeywordSet, entity} = require '../utils' 2 | {identifierCharSet} = require '../parser/base' 3 | 4 | hasOwnProperty = Object::hasOwnProperty 5 | 6 | toIdentifier = (symbol) -> 7 | result = '' 8 | for c in symbol 9 | if identifierCharSet[c] then result += c 10 | else result += '$' 11 | if javascriptKeywordSet[symbol] then result += '1' 12 | result 13 | 14 | error = (msg, exp) -> 15 | if exp then throw Error msg+': '+exp 16 | else throw Error msg 17 | 18 | class SymbolLookupError extends Error 19 | constructor: (@msg, @exp) -> 20 | 21 | # options: {module, functionInfo, parser, ...} 22 | exports.Environment = class Environment 23 | constructor: (@scope, @parent, @parser, @module, @functionInfo, @options) -> 24 | if functionInfo 25 | functionInfo['backFillBlock!'] = [] 26 | @localScopeLevel = 0 27 | else @localScopeLevel = parent.localScopeLevel+1 28 | if parent then @meta = parent.meta 29 | else @meta = {list: [], code: [], index:0, env: @extend({})} 30 | 31 | extend: (scope, parser, module, functionInfo, options) -> 32 | new Environment(scope or @scope, @, parser or @parser, module or @module, functionInfo, options or @options) 33 | 34 | getFunctionInfo: -> 35 | env = @ 36 | while not functionInfo = env.functionInfo then env = env.parent 37 | functionInfo 38 | 39 | getFunctionEnv: -> 40 | env = @ 41 | while not env.functionInfo then env = env.parent 42 | env 43 | 44 | newVar: (symbol) -> 45 | name = toIdentifier(symbol) 46 | functionInfo = @getFunctionInfo() 47 | if not hasOwnProperty.call(functionInfo, name) 48 | functionInfo[name] = 1; {symbol: name} 49 | else 50 | while symbolIndex = name+(++functionInfo[name]) 51 | if not hasOwnProperty.call(functionInfo, symbolIndex) then break 52 | functionInfo[symbolIndex] = 1 53 | {symbol: symbolIndex} 54 | 55 | constVar: (symbol) -> v = @newVar(symbol); v.const = true; v 56 | ssaVar: (symbol) -> v = @newVar(symbol); v.ssa = true; v 57 | 58 | #__taiji$AnyIdentifier__ -> __taiji$AnyIdentifier???__, where ??? is index to avoid conflicting 59 | newTaijiVar: (symbol) -> 60 | name = toIdentifier(symbol) 61 | functionInfo = @getFunctionInfo() 62 | if not hasOwnProperty.call(functionInfo, name) 63 | functionInfo[name] = 1; {symbol: name} 64 | else 65 | while symbolIndex = name[...name.length-2]+(++functionInfo[name])+name[name.length-2...] 66 | if not hasOwnProperty.call(functionInfo, symbolIndex) then break 67 | functionInfo[symbolIndex] = 1 68 | {symbol: symbolIndex} 69 | 70 | getSymbolIndex: (symbol) -> 71 | functionInfo = @getFunctionInfo() 72 | if not hasOwnProperty.call(functionInfo, symbol) then return 0 73 | else return functionInfo[symbol] 74 | 75 | hasLocal: (symbol) -> hasOwnProperty.call(@scope, symbol) 76 | 77 | hasFnLocal: (symbol) -> 78 | if hasOwnProperty.call(@scope, symbol) then return true 79 | if @functionInfo then return 80 | else if @parent then return @parent.hasFnLocal(symbol) 81 | 82 | # all variables name relating to symbol 83 | fnLocalNames: (symbol) -> 84 | names = {} 85 | env = @ 86 | while 1 87 | if env.scope and hasOwnProperty.call(env.scope, symbol) 88 | names[env.scope[symbol].symbol] = 1 89 | if env.functionInfo then return names 90 | else if env.parent then env = env.parent 91 | else return names 92 | 93 | # use @@x to get variable x in outer var scope( outer function or module variable) 94 | outerVarScopeEnv: -> 95 | parent = @ 96 | while 1 97 | if parent.functionInfo 98 | if parent.parent then return parent.parent 99 | else return @ # instead of returning parent, return @. because the check in core.coffee exports['='] if env!=outerEnv and env.get(name) 100 | else parent = parent.parent 101 | 102 | set: (symbol, value) -> 103 | functionInfo = @getFunctionInfo() 104 | if typeof(value) == 'object' then value.value = name = toIdentifier(entity(value)) 105 | else value = name = toIdentifier(value) 106 | if not functionInfo[name] then functionInfo[name] = 1 107 | eValue = entity(value) 108 | if not functionInfo[eValue] then functionInfo[eValue] = 1 109 | @scope[symbol] = value 110 | 111 | get: (symbol) -> 112 | if hasOwnProperty.call(@scope, symbol) then return @scope[symbol] 113 | else if @parent then return @parent.get(symbol) 114 | 115 | info: (symbol) -> 116 | if @optimizeInfoMap and hasOwnProperty.call(@optimizeInfoMap, symbol) then return @optimizeInfoMap[symbol] 117 | else if @parent then return @parent.info(symbol) 118 | 119 | # analysis and optimization use the same environment, but add the property "optimizeInfoMap" to the env instance 120 | # the root env is the initial env which is be used to convert and transform the exp 121 | # when 'function!' is met, the corresponding env is used. -------------------------------------------------------------------------------- /src/compiler/package.json: -------------------------------------------------------------------------------- 1 | {"main":"compile.js"} -------------------------------------------------------------------------------- /src/module.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | path = require 'path' 3 | 4 | # If obj.hasOwnProperty has been overridden, then calling obj.hasOwnProperty(prop) will break. 5 | # See: https:# github.com/joyent/node/issues/1707 6 | hasOwnProperty = (obj, prop) -> Object.prototype.hasOwnProperty.call(obj, prop) 7 | 8 | modulePaths = [] 9 | #console.log modulePaths 10 | 11 | module.exports = exports = TaijiModule = (filePath, @parent) -> 12 | @exports = {} # meta exports for the module 13 | if not filePath 14 | if @parent then @filePath = @parent.filePath 15 | else @filePath = __filename 16 | else if not @parent then @filePath = filePath 17 | else @filePath = @parent.findPath(filePath) 18 | @basePath = path.dirname(@filePath) 19 | if @parent 20 | @modulePaths = @parent.modulePaths.slice() 21 | @modulePaths.unshift path.resolve(@basePath, '../taiji-libraries') 22 | else 23 | #console.log modulePaths 24 | @modulePaths = modulePaths.slice() 25 | @modulePaths.unshift path.resolve(@basePath, '../taiji_modules') 26 | return this 27 | 28 | TaijiModule._initPaths = -> 29 | if process.env['TAIJILANG_PATH'] 30 | splitter = if process.platform == 'win32' then ';' else ':' 31 | paths = process.env['TAIJILANG_PATH'].split(splitter) 32 | for path1, i in paths then paths[i] = path.resolve(path1, 'taiji-libraries') 33 | else 34 | paths = [] 35 | # console.log paths 36 | modulePaths = paths 37 | 38 | # console.log 'initpaths' 39 | TaijiModule._initPaths() 40 | 41 | # In order to minimize unnecessary lstat() calls, this cache is a list of known-real paths. Set to an empty object to reset. 42 | _realpathCache = {} 43 | 44 | # check if the file exists and is not a directory 45 | tryFile = (requestPath) -> 46 | try 47 | stats = fs.statSync(requestPath) 48 | if stats && !stats.isDirectory() then fs.realpathSync(requestPath, _realpathCache) 49 | catch ex then return false 50 | 51 | tryPath = (filePath, trailingSlash) -> 52 | if !trailingSlash 53 | filename = tryFile(filePath) 54 | if !filename && filePath.slice(-3)!='.tj' 55 | filename = tryFile(filePath + '.tj') 56 | if !filename 57 | mainPath = path.resolve(filePath, 'main.tj') 58 | filename = tryFile(mainPath) 59 | filename 60 | 61 | TaijiModule.matchPaths = (request, paths) -> 62 | trailingSlash = request.slice(-1) == '/' 63 | for path1 in paths 64 | if filename = tryPath path.resolve(path1, request), trailingSlash then return filename 65 | 66 | TaijiModule::findPath = (filePath) -> 67 | if filePath=='**evaluated taijilang code**' then return filePath 68 | if fs.exists(filePath) then return filePath 69 | start = filePath.substring(0, 2) 70 | if start=='./' or start=='.\\' or start=='..' 71 | trailingSlash = filePath.slice(-1) == '/' 72 | filename = tryPath(path.resolve(@basePath, filePath), trailingSlash) 73 | else 74 | if filePath.charAt(0) == '/' then paths = [''] # absolute path, no other paths is searched 75 | else paths = @modulePaths 76 | filename = TaijiModule.matchPaths(filePath, paths) 77 | if !filename 78 | err = new Error("Cannot find module '" + filePath + "'") 79 | err.code = 'MODULE_NOT_FOUND' 80 | throw err 81 | return filename -------------------------------------------------------------------------------- /src/optparse.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/optparse.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | ### 6 | ### 7 | Copyright (c) 2009-2014 Jeremy Ashkenas 8 | Copyright (c) 2014-2015 Caoxingming 9 | 10 | Permission is hereby granted, free of charge, to any person 11 | obtaining a copy of this software and associated documentation 12 | files (the "Software"), to deal in the Software without 13 | restriction, including without limitation the rights to use, 14 | copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the 16 | Software is furnished to do so, subject to the following 17 | conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | ### 31 | 32 | # A simple **OptionParser** class to parse option flags from the command-line. 33 | # Use it like so: 34 | # parser = new OptionParser switches, helpBanner 35 | # options = parser.parse process.argv 36 | # The first non-option is considered to be the start of the file (and file 37 | # option) list, and all subsequent arguments are left unparsed. 38 | exports.OptionParser = class OptionParser 39 | # Initialize with a list of valid options, in the form: 40 | # [short-flag, long-flag, description] 41 | # Along with an an optional banner for the usage help. 42 | constructor: (rules, @banner) -> 43 | @rules = buildRules rules 44 | 45 | # Parse the list of arguments, populating an `options` object with all of the 46 | # specified options, and return it. Options after the first non-option 47 | # argument are treated as arguments. `options.arguments` will be an array 48 | # containing the remaining arguments. This is a simpler API than many option 49 | # parsers that allow you to attach callback actions for every flag. Instead, 50 | # you're responsible for interpreting the options object. 51 | parse: (args) -> 52 | options = arguments: [] 53 | skippingArgument = no 54 | originalArgs = args 55 | args = normalizeArguments args 56 | for arg, i in args 57 | if skippingArgument 58 | skippingArgument = no 59 | continue 60 | if arg is '--' 61 | pos = originalArgs.indexOf '--' 62 | options.arguments = options.arguments.concat originalArgs[(pos + 1)..] 63 | break 64 | isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG)) 65 | # the CS option parser is a little odd; options after the first 66 | # non-option argument are treated as non-option arguments themselves 67 | seenNonOptionArg = options.arguments.length > 0 68 | unless seenNonOptionArg 69 | matchedRule = no 70 | for rule in @rules 71 | if rule.shortFlag is arg or rule.longFlag is arg 72 | value = true 73 | if rule.hasArgument 74 | skippingArgument = yes 75 | value = args[i + 1] 76 | options[rule.name] = if rule.isList then (options[rule.name] or []).concat value else value 77 | matchedRule = yes 78 | break 79 | throw new Error "unrecognized option: #{arg}" if isOption and not matchedRule 80 | if seenNonOptionArg or not isOption 81 | options.arguments.push arg 82 | options 83 | 84 | # Return the help text for this **OptionParser**, listing and describing all 85 | # of the valid options, for `--help` and such. 86 | help: -> 87 | lines = [] 88 | lines.unshift "#{@banner}\n" if @banner 89 | for rule in @rules 90 | spaces = 15 - rule.longFlag.length 91 | spaces = if spaces > 0 then repeat ' ', spaces else '' 92 | letPart = if rule.shortFlag then rule.shortFlag + ', ' else ' ' 93 | lines.push ' ' + letPart + rule.longFlag + spaces + rule.description 94 | "\n#{ lines.join('\n') }\n" 95 | 96 | # Regex matchers for option flags. 97 | LONG_FLAG = /^(--\w[\w\-]*)/ 98 | SHORT_FLAG = /^(-\w)$/ 99 | MULTI_FLAG = /^-(\w{2,})/ 100 | OPTIONAL = /\[(\w+(\*?))\]/ 101 | 102 | # Build and return the list of option rules. If the optional *short-flag* is 103 | # unspecified, leave it out by padding with `null`. 104 | buildRules = (rules) -> 105 | for tuple in rules 106 | tuple.unshift null if tuple.length < 3 107 | buildRule tuple... 108 | 109 | # Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the 110 | # description of what the option does. 111 | buildRule = (shortFlag, longFlag, description, options = {}) -> 112 | match = longFlag.match(OPTIONAL) 113 | longFlag = longFlag.match(LONG_FLAG)[1] 114 | { 115 | name: longFlag.substr 2 116 | shortFlag: shortFlag 117 | longFlag: longFlag 118 | description: description 119 | hasArgument: !!(match and match[1]) 120 | isList: !!(match and match[2]) 121 | } 122 | 123 | # Normalize arguments by expanding merged flags into multiple flags. This allows 124 | # you to have `-wl` be the same as `--watch --lint`. 125 | normalizeArguments = (args) -> 126 | args = args[..]; result = [] 127 | for arg in args 128 | if match = arg.match MULTI_FLAG then result.push '-' + l for l in match[1].split '' 129 | else result.push arg 130 | result 131 | 132 | # Repeat a string `n` times. 133 | repeat = (str, n) -> 134 | # Use clever algorithm to have O(log(n)) string concatenation operations. 135 | res = '' 136 | while n > 0 137 | res += str if n & 1 138 | n >>>= 1 139 | str += str 140 | res 141 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | {"main":"taiji.js"} -------------------------------------------------------------------------------- /src/parser/base.coffee: -------------------------------------------------------------------------------- 1 | utils = require '../utils' 2 | 3 | exports.entity = utils.entity 4 | exports.debug = utils.debug 5 | exports.warn = utils.warn 6 | exports.str = str = utils.str 7 | exports.convertIdentifier = utils.convertIdentifier 8 | exports.isArray = utils.isArray 9 | exports.extend = utils.extend 10 | exports.wrapInfo1 = utils.wrapInfo1 11 | exports.wrapInfo2 = utils.wrapInfo2 12 | exports.charset = charset = utils.charset 13 | 14 | exports.digits = digits = '0123456789' 15 | exports.lowers = lowers = 'abcdefghijklmnopqrstuvwxyz' 16 | exports.uppers = uppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 17 | exports.letters = letters = lowers+uppers 18 | exports.letterDigits = letterDigits = letters+digits 19 | exports.letterDigitSet = charset letterDigits 20 | exports.firstIdentifierChars = firstIdentifierChars = '$_'+letters 21 | exports.identifierChars = identifierChars = firstIdentifierChars+digits 22 | exports.taijiIdentifierChars = taijiIdentifierChars = '!?'+identifierChars 23 | exports.digitCharSet = digitCharSet = charset(exports.digits) 24 | exports.letterCharSet = letterCharSet = charset(exports.letters) 25 | exports.firstIdentifierCharSet = charset('$_'+letters) 26 | exports.identifierCharSet = identifierCharSet = charset(identifierChars) 27 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars) 28 | exports.taijiIdentifierCharSet = taijiIdentifierCharSet = charset(taijiIdentifierChars) 29 | 30 | NUMBER=1; STRING=2; IDENTIFIER=3; SYMBOL=4; REGEXP=5; HEAD_SPACES=6; CONCAT_LINE=7; PUNCT=8; FUNCTION=9 31 | BRACKET=10; PAREN=11; DATA_BRACKET=12; CURVE=13; INDENT_EXPRESSION=14 32 | NEWLINE=15; SPACES=16; INLINE_COMMENT=17; SPACES_INLINE_COMMENT=18; LINE_COMMENT=19; BLOCK_COMMENT=20; CODE_BLOCK_COMMENT=21; CONCAT_LINE=22 33 | MODULE_HEADER=23; MODULE=24 34 | NON_INTERPOLATE_STRING=25; INTERPOLATE_STRING=26 35 | INDENT=27; UNDENT=28; HALF_DENT=29; EOI=30; C_BLOCK_COMMENT = 31; SPACE_COMMENT = 32; TAIL_COMMENT=33 36 | #PAREN_OPERATOR_EXPRESSION=33; COMPACT_CLAUSE_EXPRESSION=34; SPACE_CLAUSE_EXPRESSION=35 37 | 38 | exports.constant = {NUMBER, STRING, IDENTIFIER, SYMBOL, REGEXP, HEAD_SPACES, CONCAT_LINE, PUNCT, FUNCTION, 39 | BRACKET, PAREN, DATA_BRACKET, CURVE, INDENT_EXPRESSION 40 | NEWLINE, SPACES, INLINE_COMMENT, SPACES_INLINE_COMMENT, LINE_COMMENT, BLOCK_COMMENT, CODE_BLOCK_COMMENT, CONCAT_LINE 41 | MODULE_HEADER, MODULE 42 | NON_INTERPOLATE_STRING, INTERPOLATE_STRING 43 | INDENT, UNDENT, HALF_DENT, EOI, C_BLOCK_COMMENT, SPACE_COMMENT, TAIL_COMMENT 44 | #PAREN_OPERATOR_EXPRESSION, COMPACT_CLAUSE_EXPRESSION, SPACE_CLAUSE_EXPRESSION 45 | } -------------------------------------------------------------------------------- /src/parser/package.json: -------------------------------------------------------------------------------- 1 | {"main":"parser.js"} -------------------------------------------------------------------------------- /src/register.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/register.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | ### 6 | ### 7 | Copyright (c) 2009-2014 Jeremy Ashkenas 8 | Copyright (c) 2014-2015 Caoxingming 9 | 10 | Permission is hereby granted, free of charge, to any person 11 | obtaining a copy of this software and associated documentation 12 | files (the "Software"), to deal in the Software without 13 | restriction, including without limitation the rights to use, 14 | copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the 16 | Software is furnished to do so, subject to the following 17 | conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | ### 31 | 32 | child_process = require 'child_process' 33 | path = require 'path' 34 | taiji = require './taiji' 35 | utils = require './utils' 36 | 37 | # Load and run a taiji file for Node, stripping any `BOM`s. 38 | loadFile = (module, filename) -> 39 | answer = taiji._compileFile filename, false 40 | module._compile answer, filename 41 | 42 | # If the installed version of Node supports `require.extensions`, register taiji as an extension. 43 | if require.extensions 44 | for ext in taiji.FILE_EXTENSIONS then require.extensions[ext] = loadFile 45 | 46 | # Patch Node's module loader to be able to handle multi-dot extensions. 47 | # This is a horrible thing that should not be required. 48 | Module = require 'module' 49 | 50 | findExtension = (filename) -> 51 | extensions = path.basename(filename).split '.' 52 | # Remove the initial dot from dotfiles. 53 | extensions.shift() if extensions[0] is '' 54 | # Start with the longest possible extension and work our way shortwards. 55 | while extensions.shift() 56 | curExtension = '.' + extensions.join '.' 57 | return curExtension if Module._extensions[curExtension] 58 | '.js' 59 | 60 | Module::load = (filename) -> 61 | @filename = filename 62 | @paths = Module._nodeModulePaths path.dirname filename 63 | extension = findExtension filename 64 | Module._extensions[extension](this, filename) 65 | @loaded = true 66 | 67 | # If we're on Node, patch `child_process.fork` so that taiji scripts are able to fork both taiji files, and JavaScript files, directly. 68 | if child_process 69 | {fork} = child_process 70 | binary = require.resolve '../bin/taiji' 71 | child_process.fork = (path, args, options) -> 72 | if utils.isTaiji path 73 | unless Array.isArray args then options = args or {}; args = [] 74 | args = [path].concat args 75 | path = binary 76 | fork path, args, options 77 | -------------------------------------------------------------------------------- /src/repl.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | this file is based on coffeescript/src/repl.coffee(https://github.com/jashkenas/coffeescript) 3 | Thanks to Jeremy Ashkenas 4 | Some stuffs is added or modified for taiji langauge. 5 | ### 6 | ### 7 | Copyright (c) 2009-2014 Jeremy Ashkenas 8 | Copyright (c) 2014-2015 Caoxingming 9 | 10 | Permission is hereby granted, free of charge, to any person 11 | obtaining a copy of this software and associated documentation 12 | files (the "Software"), to deal in the Software without 13 | restriction, including without limitation the rights to use, 14 | copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the 16 | Software is furnished to do so, subject to the following 17 | conditions: 18 | 19 | The above copyright notice and this permission notice shall be 20 | included in all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | OTHER DEALINGS IN THE SOFTWARE. 30 | ### 31 | 32 | fs = require 'fs' 33 | path = require 'path' 34 | vm = require 'vm' 35 | nodeREPL = require 'repl' 36 | {Environment, compileExp, textizerOptions} = taiji = require './taiji' 37 | {extend, merge, updateSyntaxError} = require './utils' 38 | 39 | options = extend {}, textizerOptions 40 | parser = new taiji.Parser 41 | env = new Environment extend({}, taiji.builtins), null, {} 42 | 43 | replDefaults = 44 | prompt: 'taiji: ', 45 | historyFile: path.join process.env.HOME, '.taiji_history' if process.env.HOME 46 | historyMaxInputSize: 10240 47 | eval: (input, context, filename, cb) -> 48 | input = input.replace /\uFF00/g, '\n' # XXX: multiline hack. 49 | input = input.replace /^\(([\s\S]*)\n\)$/m, '$1' # Node's REPL sends the input ending with a newline and then wrapped in parens. Unwrap all that. 50 | try 51 | exp = parser.parse(input, parser.moduleBody, 0, 0, 0, env) 52 | js = compileExp(exp, env, options) 53 | result = if context is global then vm.runInThisContext js, filename 54 | else vm.runInContext js, context, filename 55 | cb null, result 56 | catch err 57 | updateSyntaxError err, input 58 | cb err 59 | 60 | addMultilineHandler = (repl) -> 61 | {rli, inputStream, outputStream} = repl 62 | 63 | multiline = 64 | enabled: off 65 | initialPrompt: repl.prompt.replace /^[^> ]*/, (x) -> x.replace /./g, '-' 66 | prompt: repl.prompt.replace /^[^> ]*>?/, (x) -> x.replace /./g, '.' 67 | buffer: '' 68 | 69 | # Proxy node's line listener 70 | nodeLineListener = rli.listeners('line')[0] 71 | rli.removeListener 'line', nodeLineListener 72 | rli.on 'line', (cmd) -> 73 | if multiline.enabled 74 | multiline.buffer += "#{cmd}\n" 75 | rli.setPrompt multiline.prompt 76 | rli.prompt true 77 | else nodeLineListener cmd 78 | return 79 | 80 | # Handle Ctrl-v 81 | inputStream.on 'keypress', (char, key) -> 82 | return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v' 83 | if multiline.enabled 84 | # allow arbitrarily switching between modes any time before multiple lines are entered 85 | unless multiline.buffer.match /\n/ 86 | multiline.enabled = not multiline.enabled 87 | rli.setPrompt repl.prompt 88 | rli.prompt true 89 | return 90 | # no-op unless the current line is empty 91 | return if rli.line? and not rli.line.match /^\s*$/ 92 | # eval, print, loop 93 | multiline.enabled = not multiline.enabled 94 | rli.line = '' 95 | rli.cursor = 0 96 | rli.output.cursorTo 0 97 | rli.output.clearLine 1 98 | # XXX: multiline hack 99 | multiline.buffer = multiline.buffer.replace /\n/g, '\uFF00' 100 | rli.emit 'line', multiline.buffer 101 | multiline.buffer = '' 102 | else 103 | multiline.enabled = not multiline.enabled 104 | rli.setPrompt multiline.initialPrompt 105 | rli.prompt true 106 | return 107 | 108 | # Store and load command history from a file 109 | addHistory = (repl, filename, maxSize) -> 110 | lastLine = null 111 | try 112 | # Get file info and at most maxSize of command history 113 | stat = fs.statSync filename 114 | size = Math.min maxSize, stat.size 115 | # Read last `size` bytes from the file 116 | readFd = fs.openSync filename, 'r' 117 | buffer = new Buffer(size) 118 | fs.readSync readFd, buffer, 0, size, stat.size - size 119 | # Set the history on the interpreter 120 | repl.rli.history = buffer.toString().split('\n').reverse() 121 | # If the history file was truncated we should pop off a potential partial line 122 | repl.rli.history.pop() if stat.size > maxSize 123 | # Shift off the final blank newline 124 | repl.rli.history.shift() if repl.rli.history[0] is '' 125 | repl.rli.historyIndex = -1 126 | lastLine = repl.rli.history[0] 127 | 128 | fd = fs.openSync filename, 'a' 129 | 130 | repl.rli.addListener 'line', (code) -> 131 | if code and code.length and code isnt '.history' and lastLine isnt code 132 | # Save the latest command in the file 133 | fs.write fd, "#{code}\n" 134 | lastLine = code 135 | 136 | repl.rli.on 'exit', -> fs.close fd 137 | 138 | # Add a command to show the history stack 139 | repl.commands['.history'] = 140 | help: 'Show command history' 141 | action: -> 142 | repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n" 143 | repl.displayPrompt() 144 | 145 | module.exports = 146 | start: (opts = {}) -> 147 | [major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n) 148 | 149 | if major is 0 and minor < 8 150 | console.warn "Node 0.8.0+ required for taiji REPL" 151 | process.exit 1 152 | 153 | taiji.register() 154 | process.argv = ['taiji'].concat process.argv[2..] 155 | opts = merge replDefaults, opts 156 | repl = nodeREPL.start opts 157 | repl.on 'exit', -> repl.outputStream.write '\n' 158 | addMultilineHandler repl 159 | addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile 160 | # Correct the description inherited from the node REPL 161 | repl.commands['.load'].help = 'Load code from a file into this REPL session' 162 | repl 163 | -------------------------------------------------------------------------------- /src/taiji.coffee: -------------------------------------------------------------------------------- 1 | # The current taiji version number. 2 | exports.VERSION = '0.1.0' 3 | 4 | {extend, begin, formatTaijiJson, addPrelude} = require './utils' 5 | TaijiModule = require './module' 6 | {Parser} = require './parser' 7 | {entity} = require './parser/base' 8 | exports.Parser = Parser 9 | {Environment, metaConvert, transformExp, optimizeExp, compileExp, metaCompile, compileExpNoOptimize} = require './compiler' 10 | exports.Environment = Environment 11 | exports.compileExp = compileExp 12 | exports.builtins = extend {}, require('./builtins/core'), require('./builtins/js') 13 | 14 | exports.textizerOptions = textizerOptions = { 15 | indentWidth: 2, lineLength: 80 16 | } 17 | 18 | exports.rootModule = rootModule = new TaijiModule(__filename, null) 19 | 20 | exports.initEnv = initEnv = (builtins, taijiModule, options) -> 21 | options = extend options, textizerOptions 22 | # Environment(scope=builtins, parent=null, new Parser, taijiModule, newVarIndexMap={}, options) 23 | env = new Environment(extend({}, builtins), null, new Parser, taijiModule, {}, options) 24 | env.parser = new Parser 25 | env 26 | 27 | exports.parse = (code, taijiModule, builtins, options) -> 28 | env = initEnv(builtins, taijiModule, options); parser = env.parser 29 | exp = parser.parse(code, parser.module, 0, env) 30 | formatTaijiJson(entity(exp.body), 0, 0, false, 2, 70) 31 | 32 | exports.convert = (code, taijiModule, builtins, options) -> 33 | env = initEnv(builtins, taijiModule, options); parser = env.parser 34 | exp = parser.parse(code, parser.module, 0, env) 35 | exp = metaConvert(addPrelude(parser, exp.body), env) 36 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 37 | 38 | exports.transform = (code, taijiModule, builtins, options) -> 39 | env = initEnv(builtins, taijiModule, options); parser = env.parser 40 | exp = parser.parse(code, parser.module, 0, env) 41 | exp = transformExp(addPrelude(parser, exp.body), env) 42 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 43 | 44 | exports.optimize = (code, taijiModule, builtins, options) -> 45 | env = initEnv(builtins, taijiModule, options); parser = env.parser 46 | exp = parser.parse(code, parser.module, 0, env) 47 | exp = optimizeExp(addPrelude(parser, exp.body), env) 48 | formatTaijiJson(entity(exp), 0, 0, false, 2, 70) 49 | 50 | exports.compileInteractive = compileInteractive = (code, taijiModule, builtins, options) -> 51 | env = initEnv(builtins, taijiModule, options); parser = env.parser 52 | exp = parser.parse(code, parser.moduleBody, 0, env) 53 | objCode = compileExp(exp, env) 54 | 55 | exports.metaCompile = (code, taijiModule, builtins, options) -> 56 | env = initEnv(builtins, taijiModule, options); parser = env.parser 57 | exp = parser.parse(code, parser.module, 0, env) 58 | objCode = metaCompile(addPrelude(parser, exp.body), [], env) 59 | 60 | exports.compile = compile = (code, taijiModule, builtins, options) -> 61 | env = initEnv(builtins, taijiModule, options); parser = env.parser 62 | exp = parser.parse(code, parser.module, 0, env) 63 | objCode = compileExp(addPrelude(parser, exp.body), env) 64 | 65 | exports.compileNoOptimize = (code, taijiModule, builtins, options) -> 66 | env = initEnv(builtins, taijiModule, options); parser = env.parser 67 | exp = parser.parse(code, parser.module, 0, env) 68 | objCode = compileExpNoOptimize(addPrelude(parser, exp.body), env) 69 | 70 | exports.eval = (code, taijiModule, builtins, options) -> 71 | x = compile(code, taijiModule, builtins, options) 72 | eval x 73 | 74 | exports.FILE_EXTENSIONS = ['.taiji', '.tj'] 75 | 76 | exports.register = -> require './register' 77 | 78 | # Throw error with deprecation warning when depending upon implicit `require.extensions` registration 79 | if require.extensions 80 | for ext in exports.FILE_EXTENSIONS 81 | require.extensions[ext] ?= -> 82 | throw new Error """ 83 | Use taiji.register() or require the taiji/register module to require #{ext} files. 84 | """ -------------------------------------------------------------------------------- /taiji-libraries/browser.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this file is not tested. 4 | 5 | Shortcuts for usage in browser 6 | Usage: 7 | $ "mydiv" same as document.getElementById "mydiv" 8 | $listener domObject eventType (expression) 9 | Event Object is available to the exoressions as "event" 10 | 11 | extern! document 12 | 13 | $ #= (id) -> ` document.getElementById ^id 14 | 15 | $ # 'sdf' 16 | 17 | $listener #= (domObj, eventName, rest...) -> 18 | ` (^domObj).addEventListener ^eventName (event) -> ^&rest 19 | 20 | $listener # {var a = document}, 'dasf', print 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /taiji-libraries/class@.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this file is not tested 4 | 5 | include! 'types@.tj' 6 | 7 | __extends = (child, parent) -> 8 | for key of parent then if __hasProp.call(parent, key) then child[key] = parent[key] 9 | ctor = -> @constructor = child 10 | ctor:: = parent:: 11 | child:: = new ctor 12 | child.__super__ = parent:: 13 | child 14 | 15 | #{ 16 | var \class 17 | utils = require('../utils') 18 | entity = utils.entity 19 | error = utils.error 20 | begin = utils.begin 21 | isDefinition = (item) -> 22 | if not item then return 23 | if not isArray(item) then return 24 | item0 = entity item[0] 25 | item0=='|->' or item0=='|=>' or item0=='->' or item0=='=>' 26 | 27 | superCall = (className, args, member) -> ['callByThis!', ['attribute!', ['attribute!', className, '__super__'], member], args] 28 | 29 | convertClassMemberBody = (item, className, member) -> 30 | eItem = entity item 31 | if typeof eItem == 'string' then 32 | if eItem=='super' then return superCall(className, [], member) 33 | else return item 34 | else if not isArray(item) then return item 35 | else if isDefinition(item) then return item 36 | else if not item.length then return 37 | else 38 | item0 = entity item[0] 39 | if item0=='super' then return superCall(className, item.slice(1), member) 40 | else if item0=='call!' and entity(item[1])=='super' then 41 | return superCall(className, item[2], member) 42 | else for e in item0 then convertClassMemberBody(e, className, member) 43 | 44 | convertClassStatement = (item, className) -> 45 | if not isArray(item) then return item 46 | else if item0=entity(item[0]) and item0=='class' then return \class item[1] item[2] item[3] 47 | else if item0=='=' then 48 | if isArray(item[1]) then // ::member = value 49 | if item1=item[1] and item1[0]=='attribute!' and entity(item1[1])=='::' then 50 | member = item1[2]; var value = item[2] 51 | if isDefinition(value) then 52 | body = convertClassMemberBody(value[2], className, member) 53 | value = [value[0], value[1], body] 54 | return ['=', ['attribute!', ['attribute!', className, 'prototype'], member], value] 55 | else value = convertClassStatement(value, className) 56 | if isDefinition(item) then return item 57 | else return for x in item then convertClassStatement(x, className) 58 | 59 | \class = (className, superClass, body) -> 60 | result = ['begin!'] 61 | // class name must be provided explicitly 62 | // if not className then className = newvar! '_class'; result.push `{const ^className} 63 | // if constructor is provided, then it must be the first statement of the body 64 | //console.log entity(className) 65 | //print: entity superClass 66 | if not isArray(body) then 67 | result.push `{ \= ^className -> } 68 | if superClass then result.push `{__extends ^className ^superClass} 69 | result.push body 70 | return result 71 | if body0=body[0] and entity(body0[0])=='=' and entity(body0[1])=='::' then 72 | var index = 1 73 | body02 = body0[2] 74 | if not isDefinition(body02) then error 'wrongly use non function as the constructor of a class '+className 75 | if superClass then 76 | ctorBody = convertClassMemberBody(body02[2], className, 'constructor') 77 | result.push `{\= ^className ^[body02[0], body02[1], ctorBody]} 78 | result.push `{__extends ^className ^superClass} 79 | else result.push `{ \= ^className ^body02 } 80 | else 81 | index = 0 82 | result.push `{ \= ^className -> } 83 | if superClass then result.push `{__extends ^className ^superClass} 84 | classBody = [] 85 | for item in body.slice(index) then 86 | classBody.push convertClassStatement(item, className) 87 | result.push ['block!', begin(classBody)] 88 | begin result 89 | } 90 | undefined -------------------------------------------------------------------------------- /taiji-libraries/html.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this file is not tested 4 | 5 | !-- #= (rest...) -> "" 6 | 7 | //str! #/= (args...) -> '""' 8 | str! #= (args...) -> '""' 9 | // str! = (args...) -> '""' 10 | 11 | extern! isString isObject templateRepeatKey key value 12 | exports.expandTag = expandTag = (name, args...) -> 13 | if isString name then 14 | var ret = "<" + name 15 | if isObject args[0] then 16 | attr = args.shift() 17 | ret += templateRepeatKey attr " " key "=" "\"" value "\"" 18 | if args.length>0 || name=="script" then 19 | //ret = str! # ret, ">", args.join(""), "" 20 | else ret += "/>" 21 | ret 22 | else "" 23 | 24 | tagNames = ' 25 | a abbr address area article aside audio b base bdi bdo blockquote body br button canvas 26 | caption cite code col colgroup command data datalist dd del details dfn div dl dt em embed fieldset 27 | figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins 28 | kbd keygen label legend li link map mark menu meta meter nav noscript object ol optgroup option 29 | output p param pre progress q rest rt rest rp ruby s samp progress script section select small source span 30 | strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul video wbr' 31 | 32 | /.for tag in tagNames.split ' ' then 33 | exports[tag] = (rest...) -> expandTag tag rest 34 | 35 | exports['var_'] = (rest...) -> expandTag 'var' rest 36 | 37 | x #= -> 1 38 | 39 | export! #x, y = 1 -------------------------------------------------------------------------------- /taiji-libraries/macros.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | this program is used to demonstrate and test compilation, not a part of bootstrap of taijilang. 4 | this program is not tested yet. 5 | 6 | /...................... Expressions ............................. 7 | extern! \do 8 | 9 | \when #= (cond, body...) -> `{if ^cond then ^&body} 10 | unless #= (cond, body...) -> `{if (!.^cond) then ^&body} 11 | 12 | /.cond #= (clauses...) -> 13 | //[[test, body] |- left] = clauses 14 | `[if ^test then ^&body else ^&cond(^&left)] 15 | 16 | arrayInit = (len, obj) -> 17 | ret = [] 18 | //for i=0; i 22 | ret = [] 23 | /.for i=0; i arr.forEach(rest) 32 | reduce #= (arr, rest...) -> arr.reduce(rest) 33 | /.eachKey = (obj, fn, rest...) -> (o, f, s) -> 34 | k = Object.keys(o) 35 | each k (elem) -> f.call(s, elem[o], elem, o) 36 | obj 37 | fn 38 | rest 39 | 40 | each2d #= (arr, fn) -> 41 | each arr (elem, i, oa) -> 42 | each elem (val, j, ia) -> 43 | fn val j i ia oa 44 | 45 | map = (arr, rest...) -> arr.map(rest) 46 | filter = (rest...) -> Array::filter.call(rest) 47 | some = (rest...) -> Array::some.call(rest) 48 | 49 | every = (rest...) -> Array::every.call(rest) 50 | 51 | /.loop = (args, vals, rest...) -> 52 | -> 53 | /.var recur, null, 54 | result = !undefined 55 | nextArgs = null 56 | f = (args) -> rest 57 | recur = -> 58 | nextArgs = arguments 59 | if (result == undefined) then 60 | undefined 61 | else 62 | result = undefined 63 | while (result===undefined) result = f.apply(this nextArgs) 64 | result 65 | recur(@vals) 66 | 67 | /.for = (rest...) -> 68 | doMonad arrayMonad rest 69 | 70 | # extern! str eachKey 71 | 72 | //////////////////// Templates //////////////////////////// 73 | 74 | template #= (name, args, rest...) -> 75 | name = (args) -> str rest 76 | 77 | templateRepeat #= (arg, rest...) -> 78 | reduce arg (memo, elem, index) -> 79 | memo + str(rest) "" 80 | 81 | templateRepeatKey #= (obj, rest...) -> 82 | begin! 83 | ret = "" 84 | eachKey obj (value, key) -> 85 | ret += str(rest) 86 | ret 87 | 88 | /////////////////// Callback Sequence ////////////////////; 89 | 90 | sequence #= (name, args, init, rest...) -> 91 | (args) -> 92 | -> 93 | @init 94 | curr = 0 95 | actions = new Array rest 96 | var next 97 | next = -> 98 | ne = actions[curr++] 99 | if ne then ne 100 | else throw "Call to [next] beyond sequence." 101 | next() 102 | 103 | 104 | //////////////////; Unit Testing ////////////////////////////; 105 | 106 | # extern! array Date 107 | 108 | assert #= (cond, message) -> 109 | if cond then "Passed - $message" else "Failed - $message" 110 | 111 | testGroup #= (name, rest...) -> 112 | name = -> array(rest) 113 | 114 | testRunner #= (groupname, desc)-> 115 | start = new Date 116 | tests = groupname() 117 | passed = 0 118 | failed = 0 119 | each tests (elem) -> 120 | if elem.match(/!^Passed/) then ++passed 121 | else ++failed 122 | str 123 | /.str "\n" desc "\n" start "\n\n" 124 | template-repeat tests elem "\n" 125 | "\nTotal tests ", tests.length 126 | "\nPassed ", passed 127 | "\nFailed ", failed 128 | "\nDuration " ([new Date] - start) "ms\n" // leading \ cancel generating subsexpression just concatenate to previous result] 129 | 130 | 131 | //////////////// Monads //////////////////////////////////; 132 | 133 | identityMonad #= -> 134 | {. mBind: [(mv, mf) -> mf(mv)]; mResult: [(v) -> v] .} 135 | 136 | /* 137 | maybeMonad #= -> 138 | { mBind: (mv, mf) -> if (mv==undefined) then null else mf(mv); 139 | mResult: (v) -> v; 140 | mZero: null; 141 | } 142 | 143 | 144 | arrayMonad #= -> 145 | { mBind: (mv, mf) -> 146 | reduce 147 | map mv mf 148 | (accum, val) -> accum.concat(val) 149 | [] 150 | mResult: (v) -> v() 151 | mZero: [] 152 | mPlus: -> 153 | reduce 154 | Array::slice.call arguments 155 | (accum, val) -> accum.concat(val) 156 | [] 157 | } 158 | 159 | stateMonad #= -> 160 | `{ mBind: (mv, f) -> 161 | (s) -> 162 | l = mv(s) 163 | v = l./0 164 | ss = l./1 165 | f(v)(ss) 166 | mResult: (v) -> (s) -> v(s) 167 | } 168 | 169 | continuationMonad #= -> 170 | { mBind: (mv, mf) -> (c) -> mv((v) -> mf(v)(c)) 171 | mResult: (v) -> (c) -> c(v) 172 | } 173 | 174 | m-bind = (bindings, expr) 175 | mBind #args-second(bindings) 176 | function #args-shift(bindings) 177 | #args-if bindings m-bind(bindings, expr) [function [] expr] 178 | 179 | #function withMonad [monad rest...] 180 | function [___monad] 181 | var mBind = ___monad.mBind 182 | mResult = ___monad.mResult 183 | mZero = ___monad.mZero 184 | mPlus = ___monad.mPlus 185 | rest... 186 | monad 187 | 188 | doMonad #= (monad, bindings, expr) -> 189 | withMonad monad 190 | var ____mResult 191 | function ___arg 192 | if (___arg==undefined&&mZero!=undefined) then: 193 | mZero 194 | else: mResult ___arg 195 | m-bind bindings : ____mResult expr 196 | 197 | monad #= (name, obj) -> ^name = -> ^obj 198 | */ -------------------------------------------------------------------------------- /taiji-libraries/prelude.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | This is the prelude of all of taiji language programs, it's included by the taijilang compilation process automatically. 4 | 5 | // some definitions 6 | // __taijiVersion #= '0.1.0' 7 | // __compileMode #= 'test' 8 | 9 | // used by ellipsis parameters 10 | __slice #/= [].slice // this line is added by addPrelude in utils.coffee on demand. 11 | 12 | // used by import! statement and some other scenes 13 | __hasProp #/= {. .}.hasOwnProperty 14 | 15 | /. control structure 16 | forIn 17 | forOf 18 | cFor 19 | try 20 | class -------------------------------------------------------------------------------- /taiji-libraries/types.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | some macros for small code piece to check type 4 | by use macros, we can reduce function call and optimize the performance of the program 5 | 6 | macro definition will not generate code in the object code, but macro call will. 7 | 8 | include! "./types@.tj" 9 | 10 | export! #undefined?, #null?, #true?, #false?, #boolean?, #number?, #string?, #array?, #object?, #function? 11 | export! #isArray -------------------------------------------------------------------------------- /taiji-libraries/types@.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | some macros for small code piece to check type 4 | by use macros, we can reduce function call and optimize the performance of the program 5 | 6 | macro definition will not generate code in the object code, but macro call will. 7 | 8 | undefined? #= (obj) -> `((^obj)==undefined) 9 | null? #= (obj) -> `((^obj)==null or (^obj)==undefined) 10 | true? #= (obj) -> ` !!(^obj) 11 | false? #= (obj) -> ` !(^obj) 12 | boolean? #= (obj) -> ` (typeof (^obj) == "boolean") 13 | number? #= (obj) -> `(Object::toString.call(^obj) == '[object Number]') 14 | string? #= (obj) -> ` (Object::toString.call(^obj) == '[object String]') 15 | array? #= (obj) -> ` (Object::toString.call(^obj) == '[object Array]') 16 | object? #= (obj) -> ` (Object::toString.call(^obj) == '[object Object]') 17 | function? #= (obj) -> ` (Object::toString.call(^obj) == '[object Function]') 18 | 19 | isArray #= (obj) -> (Object::toString.call(obj) == '[object Array]') 20 | 21 | /. require! usage: 22 | require! 'module' 23 | require! m1 = 'module1' 24 | require! {x, y} = m2 = 'module' 25 | require! 'abc' 'def' 26 | 27 | /.require! #= (args...) -> 28 | result = ['begin!'] 29 | for arg in args then 30 | if string? # arg then 31 | baseName = baseName(arg) 32 | result.push `{\= ^baseName {require ^arg}} 33 | else if array? # arg then 34 | if 35 | result -------------------------------------------------------------------------------- /taiji-libraries/utilities.tj: -------------------------------------------------------------------------------- 1 | taiji language 0.1 2 | 3 | some utilities for taiji language 4 | 5 | // math utilities 6 | exports.sqr! #= (n) -> ` [let x = ^n then (x * x) ] -------------------------------------------------------------------------------- /test-build/compiler/testcompileexpression.js: -------------------------------------------------------------------------------- 1 | var Environment, builtins, chai, compile, compileExp, compileExpNoOptimize, compileNoOptimize, compiler, expect, extend, idescribe, iit, initEnv, lib, ndescribe, nit, rootModule, textizerOptions, transform, _ref, _ref1; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | nit = ndescribe = function() {}; 12 | 13 | lib = '../../lib/'; 14 | 15 | _ref = require(lib + 'taiji'), Environment = _ref.Environment, textizerOptions = _ref.textizerOptions, builtins = _ref.builtins, initEnv = _ref.initEnv, rootModule = _ref.rootModule; 16 | 17 | _ref1 = compiler = require(lib + 'compiler'), compileExp = _ref1.compileExp, compileExpNoOptimize = _ref1.compileExpNoOptimize; 18 | 19 | extend = require(lib + 'utils').extend; 20 | 21 | compile = function(exp) { 22 | return compileExp(exp, initEnv(builtins, rootModule, {})); 23 | }; 24 | 25 | compileNoOptimize = function(code) { 26 | return compileExpNoOptimize(exp, initEnv(builtins, rootModule, {})); 27 | }; 28 | 29 | transform = function(exp) { 30 | return compiler.transform(exp, initEnv(builtins, rootModule, {})); 31 | }; 32 | 33 | describe("compile expression: ", function() { 34 | return describe("simple: ", function() { 35 | it('should compile 1', function() { 36 | return expect(compile(1)).to.equal('1'); 37 | }); 38 | it('should compile [\',\', [\'=\', \'x\',1], []]]', function() { 39 | return expect(compile(['binary,', ['=', 'x', 1], []])).to.equal("var x = 1;\nx, [];"); 40 | }); 41 | return it('should compile [\'binary,\', 1, []]', function() { 42 | return expect(compile(['binary,', 1, []])).to.equal("1, []"); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test-build/compiler/testcompilerdynamicgrammar.js: -------------------------------------------------------------------------------- 1 | var Parser, chai, compile, compileNoOptimize, constant, expect, idescribe, iit, isArray, lib, nit, realCode, str, taiji, _ref; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | nit = function() {}; 12 | 13 | lib = '../../lib/'; 14 | 15 | Parser = require(lib + 'parser').Parser; 16 | 17 | _ref = require(lib + 'parser/base'), constant = _ref.constant, isArray = _ref.isArray, str = _ref.str; 18 | 19 | taiji = require(lib + 'taiji'); 20 | 21 | realCode = require(lib + 'utils').realCode; 22 | 23 | compile = function(code) { 24 | var head; 25 | head = 'taiji language 0.1\n'; 26 | return realCode(taiji.compile(head + code, taiji.rootModule, taiji.builtins, {})); 27 | }; 28 | 29 | compileNoOptimize = function(code) { 30 | var head; 31 | head = 'taiji language 0.1\n'; 32 | return realCode(taiji.compileNoOptimize(head + code, taiji.rootModule, taiji.builtins, {})); 33 | }; 34 | 35 | describe("compile dyanmic syntax: ", function() { 36 | describe("compile parser attribute: ", function() { 37 | it('should compile %xyz[0]()', function() { 38 | return expect(compile('%xyz[0]()')).to.have.string("__$taiji_$_$parser__.xyz[0]()"); 39 | }); 40 | it('should compile %cursor', function() { 41 | return expect(compile('%cursor')).to.have.string("__$taiji_$_$parser__.cursor"); 42 | }); 43 | return it('should compile %char()', function() { 44 | return expect(compile('%char()')).to.have.string("__$taiji_$_$parser__.char()"); 45 | }); 46 | }); 47 | describe("parsing time evaluation: ", function() { 48 | it('should compile %% 1', function() { 49 | return expect(compile('%% 1')).to.have.string("1"); 50 | }); 51 | it('should compile %% %cursor()', function() { 52 | return expect(compile('%% %cursor()')).to.have.string("31"); 53 | }); 54 | return it('should compile %% %clause()', function() { 55 | return expect(compile('%% %clause(), 1')).to.have.string("1"); 56 | }); 57 | }); 58 | describe("parsing time evaluation macro %/: ", function() { 59 | it('should compile %/ cursor', function() { 60 | return expect(compile('%/ cursor')).to.have.string("function () {\n return cursor;\n }"); 61 | }); 62 | it('should compile %/ cursor', function() { 63 | return expect(compile('%/ cursor()')).to.have.string("30"); 64 | }); 65 | it('should compile %/ clause(), 1', function() { 66 | return expect(compile('%/ clause(), 1')).to.have.string("1"); 67 | }); 68 | return it('should compile %/ clause(), 1', function() { 69 | return expect(compile('%/ clause(), print 1')).to.have.string("console.log(1)"); 70 | }); 71 | }); 72 | describe("macro %! used by %!: ", function() { 73 | it('should compile %! cursor()', function() { 74 | return expect(compile('%! cursor()')).to.have.string("30"); 75 | }); 76 | return it('should compile %! char()', function() { 77 | return expect(compile('%! char()')).to.have.string("true"); 78 | }); 79 | }); 80 | return describe("%-then statement: ", function() { 81 | return nit('should compile % xyz then x = abc', function() { 82 | return expect(compile('% xyz then x = abc')).to.have.string("[% [xyz] [then \"= x abc\"]]"); 83 | }); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test-build/parser/testdynamicgrammar.js: -------------------------------------------------------------------------------- 1 | var chai, expect, extend, idescribe, iit, lib, ndescribe, str, taiji, _ref; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | ndescribe = function() {}; 12 | 13 | lib = '../../lib/'; 14 | 15 | _ref = require(lib + 'utils'), str = _ref.str, extend = _ref.extend; 16 | 17 | taiji = require(lib + 'taiji'); 18 | 19 | describe("parse dyanmic syntax: ", function() { 20 | var head, parse; 21 | head = 'taiji language 0.1\n'; 22 | parse = function(text) { 23 | var env, parser, x; 24 | env = taiji.initEnv(taiji.builtins, taiji.rootModule, {}); 25 | parser = env.parser; 26 | x = parser.parse(head + text, parser.module, 0, env); 27 | return str(x.body); 28 | }; 29 | it('should parse % xyz then anything here', function() { 30 | return expect(parse('% xyz then anything here')).to.equal("[object Object]"); 31 | }); 32 | it('should parse % cursor() then anything here', function() { 33 | return expect(parse('% cursor() then x = abc')).to.equal("35"); 34 | }); 35 | it('should parse % text then anything here', function() { 36 | return expect(parse('% text then anything here')).to.equal("taiji language 0.1\n% text then anything here"); 37 | }); 38 | it('should parse %% 1', function() { 39 | return expect(parse('%% 1')).to.equal("1"); 40 | }); 41 | it('should parse %/ %cursor', function() { 42 | return expect(parse('%/ %cursor')).to.equal("function () {\n return cursor;\n }"); 43 | }); 44 | it('should parse %/ cursor()', function() { 45 | return expect(parse('%/ cursor()')).to.equal("30"); 46 | }); 47 | return it('should parse %/ clause(), print 1', function() { 48 | return expect(parse('%/ clause(), print 1')).to.equal("[print 1]"); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test-build/testeval.js: -------------------------------------------------------------------------------- 1 | var chai, evaltj, expect, idescribe, iit, lib, ndescribe, taiji; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | ndescribe = function() {}; 12 | 13 | lib = '../lib/'; 14 | 15 | taiji = require(lib + 'taiji'); 16 | 17 | evaltj = function(code) { 18 | var head; 19 | head = 'taiji language 0.1\n'; 20 | return taiji["eval"](head + code, taiji.rootModule, taiji.builtins, {}); 21 | }; 22 | 23 | describe("eval: ", function() { 24 | describe("eval simple: ", function() { 25 | it('should eval 1', function() { 26 | return expect(evaltj('1')).to.equal(1); 27 | }); 28 | it('should eval \'a\'', function() { 29 | return expect(evaltj("'a'")).to.equal('a'); 30 | }); 31 | it('should eval if 1 then 2', function() { 32 | return expect(evaltj("if 1 then 2")).to.equal(2); 33 | }); 34 | it('should eval ~ 2', function() { 35 | return expect(evaltj("~ 2")).to.equal(2); 36 | }); 37 | return it('should eval 1+1', function() { 38 | return expect(evaltj("1+1")).to.equal(2); 39 | }); 40 | }); 41 | describe("statement: ", function() { 42 | it('should eval a=1', function() { 43 | return expect(evaltj("a=1")).to.equal(1); 44 | }); 45 | it('should eval a=1; a+a', function() { 46 | return expect(evaltj("a=1; a+a")).to.equal(2); 47 | }); 48 | return it('should eval let a=1 then let a = 2 then a+a', function() { 49 | return expect(evaltj("let a=1 then let a = 2 then a+a")).to.equal(4); 50 | }); 51 | }); 52 | return describe("eval 2", function() { 53 | return it('should eval "a"', function() { 54 | return expect(evaltj('"a"')).to.equal('a'); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test-build/testmodule.js: -------------------------------------------------------------------------------- 1 | var Parser, TaijiModule, chai, compile, constant, expect, idescribe, iit, isArray, lib, ndescribe, nit, path, realCode, run, str, taiji, _ref; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | ndescribe = function() {}; 12 | 13 | nit = function() {}; 14 | 15 | path = require('path'); 16 | 17 | lib = '../lib/'; 18 | 19 | Parser = require(lib + 'parser').Parser; 20 | 21 | _ref = require(lib + 'parser/base'), constant = _ref.constant, isArray = _ref.isArray, str = _ref.str; 22 | 23 | require(lib + 'compiler/compile'); 24 | 25 | taiji = require(lib + 'taiji'); 26 | 27 | TaijiModule = require(lib + 'module'); 28 | 29 | realCode = require(lib + 'utils').realCode; 30 | 31 | compile = function(code) { 32 | var head; 33 | head = 'taiji language 0.1\n'; 34 | return realCode(taiji.compile(head + code, taiji.rootModule, taiji.builtins, {})); 35 | }; 36 | 37 | run = function(code) { 38 | var head; 39 | head = 'taiji language 0.1\n'; 40 | code = taiji.compile(head + code, taiji.rootModule, taiji.builtins, {}); 41 | return str(eval(code)); 42 | }; 43 | 44 | describe("taiji module: ", function() { 45 | describe("path: ", function() { 46 | it('__dirname', function() { 47 | return expect(__dirname).to.match(/test/); 48 | }); 49 | it('__filename', function() { 50 | return expect(__filename).to.match(/test\\testmodule.js/); 51 | }); 52 | it('process.cwd', function() { 53 | return expect(process.cwd()).to.match(/taijilang/); 54 | }); 55 | it('process.execPath', function() { 56 | return expect(process.execPath).to.match(/nodejs\\node/); 57 | }); 58 | it('process.execArgv', function() { 59 | return expect(process.execArgv).to.deep.equal([]); 60 | }); 61 | return it('process.env', function() { 62 | expect(process.env['TAIJILANG_PATH']).to.match(/taijilang/); 63 | return expect(process.env['taijilang_path']).to.match(/taijilang/); 64 | }); 65 | }); 66 | describe('new module: ', function() { 67 | var taijiModule; 68 | taijiModule = new TaijiModule('f:\\taijilang\\lib\\taiji.tj', null); 69 | it('new TaijiModule', function() { 70 | expect(taijiModule.basePath).to.match(/lib/); 71 | return expect(str(taijiModule.modulePaths)).to.match(/taiji-libraries/); 72 | }); 73 | return it('should findPath', function() { 74 | var childModule; 75 | childModule = new TaijiModule('f:\\taijilang\\samples\\hello.tj', taijiModule); 76 | expect(childModule.basePath).to.equal('f:\\taijilang\\samples'); 77 | expect(childModule.findPath('.\\sample.tj')).to.equal('f:\\taijilang\\samples\\sample.tj'); 78 | return expect(childModule.findPath('html.tj')).to.equal('f:\\taijilang\\taiji-libraries\\html.tj'); 79 | }); 80 | }); 81 | return describe('include!', function() { 82 | return it('include! "./hello.tj"', function() { 83 | return expect(run("include! '../samples/hello.tj'")).to.equal("hello taiji"); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /test-build/testshell.js: -------------------------------------------------------------------------------- 1 | var chai, expect, idescribe, iit; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | require('shelljs/global'); 12 | 13 | describe("taiji shell command: ", function() { 14 | describe("experiment with shelljs: ", function() { 15 | return it('should pwd', function() { 16 | var x; 17 | x = pwd(); 18 | return expect(x).to.match(/taijilang/); 19 | }); 20 | }); 21 | it('should display node version', function() { 22 | var x; 23 | x = exec('node --version', { 24 | silent: true 25 | }).output; 26 | return expect(x).to.equal("v0.10.22\r\n"); 27 | }); 28 | it('should display taiji version', function() { 29 | var x; 30 | x = exec('node bin/taiji -v', { 31 | silent: true 32 | }).output; 33 | return expect(x).to.equal("taiji version 0.1.0\n"); 34 | }); 35 | describe("parse: ", function() { 36 | return it('should parse hello.tj', function() { 37 | var x; 38 | x = exec('node bin/taiji -o samples-js --parse samples/hello.tj', { 39 | silent: true 40 | }).output; 41 | return expect(x).to.equal(""); 42 | }); 43 | }); 44 | describe("compile file: ", function() { 45 | it('should compile hello.tj', function() { 46 | var x; 47 | x = exec('node bin/taiji -o samples-js -c samples/hello.tj', { 48 | silent: true 49 | }).output; 50 | return expect(x).to.equal(""); 51 | }); 52 | it('should compile sample.tj', function() { 53 | var x; 54 | x = exec('node bin/taiji -o samples-js -c samples/sample.tj', { 55 | silent: true 56 | }).output; 57 | return expect(x).to.equal(""); 58 | }); 59 | return it('should compile loop.tj', function() { 60 | var x; 61 | x = exec('node bin/taiji -o samples-js -c samples/loop.tj', { 62 | silent: true 63 | }).output; 64 | return expect(x).to.equal(""); 65 | }); 66 | }); 67 | return describe("run: ", function() { 68 | it('should run hello.tj', function() { 69 | var x; 70 | x = exec('node bin/taiji samples/hello.tj', { 71 | silent: true 72 | }).output; 73 | return expect(x).to.equal("hello taiji\n"); 74 | }); 75 | return it('should run sample.tj', function() { 76 | var x; 77 | x = exec('node bin/taiji samples/sample.tj', { 78 | silent: true 79 | }).output; 80 | return expect(x).to.equal("1\n7\n77\n77\n2\n2 3\n2\n2\n1\n2\n"); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test-build/testutils.js: -------------------------------------------------------------------------------- 1 | var baseFileName, chai, expect, idescribe, iit, isTaiji, lib, ndescribe, utils, _ref; 2 | 3 | chai = require("chai"); 4 | 5 | expect = chai.expect; 6 | 7 | iit = it.only; 8 | 9 | idescribe = describe.only; 10 | 11 | ndescribe = function() {}; 12 | 13 | lib = '../lib/'; 14 | 15 | _ref = utils = require(lib + 'utils'), isTaiji = _ref.isTaiji, baseFileName = _ref.baseFileName; 16 | 17 | describe("utils.coffee: ", function() { 18 | describe("isTaiji filename: ", function() { 19 | it(' 1.tj', function() { 20 | return expect(isTaiji('1.tj')).to.equal(true); 21 | }); 22 | it(' 1.taiji', function() { 23 | return expect(isTaiji('1.taiji')).to.equal(true); 24 | }); 25 | it(' 1.TAIJI', function() { 26 | return expect(isTaiji('1.TAIJI')).to.equal(false); 27 | }); 28 | it(' 1.taiji.json', function() { 29 | return expect(isTaiji('1.taiji.json')).to.equal(true); 30 | }); 31 | return it(' 1.tj.json', function() { 32 | return expect(isTaiji('1.tj.json')).to.equal(true); 33 | }); 34 | }); 35 | return describe(" baseFileName: ", function() { 36 | it(' 1.tj', function() { 37 | return expect(baseFileName('1.tj', true)).to.equal('1'); 38 | }); 39 | it(' x\\1.tj', function() { 40 | return expect(baseFileName('x\\1.tj', true, true)).to.equal('1'); 41 | }); 42 | it(' 1.taiji', function() { 43 | return expect(baseFileName('1.taiji', true)).to.equal('1'); 44 | }); 45 | it(' x\\1.taiji', function() { 46 | return expect(baseFileName('x\\1.taiji', true, true)).to.equal('1'); 47 | }); 48 | it(' x//1.taiji', function() { 49 | return expect(baseFileName('x//1.taiji', true)).to.equal('1'); 50 | }); 51 | it(' 1.taiji.json', function() { 52 | return expect(baseFileName('1.taiji.json', true)).to.equal('1'); 53 | }); 54 | return it(' 1.tj.json', function() { 55 | return expect(baseFileName('1.tj.json', true)).to.equal('1'); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/compiler/testcompileexpression.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | nit = ndescribe = -> 6 | 7 | lib = '../../lib/' 8 | {Environment, textizerOptions, builtins, initEnv, rootModule} = require lib+'taiji' 9 | {compileExp, compileExpNoOptimize} = compiler = require lib+'compiler' 10 | {extend} = require lib+'utils' 11 | 12 | compile = (exp) -> compileExp(exp, initEnv(builtins, rootModule, {})) 13 | compileNoOptimize = (code) -> compileExpNoOptimize(exp, initEnv(builtins, rootModule, {})) 14 | 15 | transform = (exp) -> 16 | compiler.transform(exp, initEnv(builtins, rootModule, {})) 17 | 18 | describe "compile expression: ", -> 19 | describe "simple: ", -> 20 | it 'should compile 1', -> 21 | expect(compile(1)).to.equal '1' 22 | it '''should compile [',', ['=', 'x',1], []]]''', -> 23 | expect(compile(['binary,', ['=', 'x',1], []])).to.equal "var x = 1;\nx, [];" 24 | it '''should compile ['binary,', 1, []]''', -> 25 | expect(compile(['binary,', 1, []])).to.equal "1, []" 26 | -------------------------------------------------------------------------------- /test/compiler/testcompilerdynamicgrammar.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | nit = -> 6 | 7 | lib = '../../lib/' 8 | {Parser} = require lib+'parser' 9 | {constant, isArray, str} = require lib+'parser/base' 10 | taiji = require lib+'taiji' 11 | {realCode} = require lib+'utils' 12 | 13 | compile = (code) -> 14 | head = 'taiji language 0.1\n' 15 | realCode taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 16 | 17 | compileNoOptimize = (code) -> 18 | head = 'taiji language 0.1\n' 19 | realCode taiji.compileNoOptimize(head+code, taiji.rootModule, taiji.builtins, {}) 20 | 21 | describe "compile dyanmic syntax: ", -> 22 | describe "compile parser attribute: ", -> 23 | it 'should compile %xyz[0]()', -> 24 | expect(compile('%xyz[0]()')).to.have.string "__$taiji_$_$parser__.xyz[0]()" 25 | it 'should compile %cursor', -> 26 | expect(compile('%cursor')).to.have.string "__$taiji_$_$parser__.cursor" 27 | it 'should compile %char()', -> 28 | expect(compile('%char()')).to.have.string "__$taiji_$_$parser__.char()" 29 | 30 | describe "parsing time evaluation: ", -> 31 | it 'should compile %% 1', -> 32 | expect(compile('%% 1')).to.have.string "1" 33 | it 'should compile %% %cursor()', -> 34 | expect(compile('%% %cursor()')).to.have.string "31" 35 | it 'should compile %% %clause()', -> 36 | expect(compile('%% %clause(), 1')).to.have.string "1" 37 | 38 | describe "parsing time evaluation macro %/: ", -> 39 | it 'should compile %/ cursor', -> 40 | expect(compile('%/ cursor')).to.have.string "function () {\n return cursor;\n }" 41 | it 'should compile %/ cursor', -> 42 | expect(compile('%/ cursor()')).to.have.string "30" 43 | it 'should compile %/ clause(), 1', -> 44 | expect(compile('%/ clause(), 1')).to.have.string "1" 45 | it 'should compile %/ clause(), 1', -> 46 | expect(compile('%/ clause(), print 1')).to.have.string "console.log(1)" 47 | 48 | describe "macro %! used by %!: ", -> 49 | it 'should compile %! cursor()', -> 50 | expect(compile('%! cursor()')).to.have.string "30" 51 | it 'should compile %! char()', -> 52 | expect(compile('%! char()')).to.have.string "true" 53 | 54 | describe "%-then statement: ", -> 55 | nit 'should compile % xyz then x = abc', -> 56 | expect(compile('% xyz then x = abc')).to.have.string "[% [xyz] [then \"= x abc\"]]" 57 | -------------------------------------------------------------------------------- /test/parser/testdynamicgrammar.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../../lib/' 8 | {str, extend} = require lib+'utils' 9 | taiji = require lib+'taiji' 10 | 11 | describe "parse dyanmic syntax: ", -> 12 | head = 'taiji language 0.1\n' 13 | parse = (text) -> 14 | env = taiji.initEnv(taiji.builtins, taiji.rootModule, {}) 15 | parser = env.parser 16 | x = parser.parse(head+text, parser.module, 0, env) 17 | str x.body 18 | it 'should parse % xyz then anything here', -> 19 | expect(parse('% xyz then anything here')).to.equal "[object Object]" 20 | it 'should parse % cursor() then anything here', -> 21 | expect(parse('% cursor() then x = abc')).to.equal "35" 22 | it 'should parse % text then anything here', -> 23 | expect(parse('% text then anything here')).to.equal "taiji language 0.1\n% text then anything here" 24 | it 'should parse %% 1', -> 25 | expect(parse('%% 1')).to.equal "1" 26 | it 'should parse %/ %cursor', -> 27 | expect(parse('%/ %cursor')).to.equal "function () {\n return cursor;\n }" 28 | it 'should parse %/ cursor()', -> 29 | expect(parse('%/ cursor()')).to.equal "30" 30 | it 'should parse %/ clause(), print 1', -> 31 | expect(parse('%/ clause(), print 1')).to.equal "[print 1]" 32 | -------------------------------------------------------------------------------- /test/testeval.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../lib/' 8 | taiji = require lib+'taiji' 9 | 10 | evaltj = (code) -> 11 | head = 'taiji language 0.1\n' 12 | taiji.eval(head+code, taiji.rootModule, taiji.builtins, {}) 13 | 14 | describe "eval: ", -> 15 | describe "eval simple: ", -> 16 | it 'should eval 1', -> 17 | expect(evaltj('1')).to.equal 1 18 | it 'should eval \'a\'', -> 19 | expect(evaltj("'a'")).to.equal 'a' 20 | it 'should eval if 1 then 2', -> 21 | expect(evaltj("if 1 then 2")).to.equal 2 22 | it 'should eval ~ 2', -> 23 | expect(evaltj("~ 2")).to.equal 2 24 | it 'should eval 1+1', -> 25 | expect(evaltj("1+1")).to.equal 2 26 | 27 | describe "statement: ", -> 28 | it 'should eval a=1', -> 29 | expect(evaltj("a=1")).to.equal 1 30 | it 'should eval a=1; a+a', -> 31 | expect(evaltj("a=1; a+a")).to.equal 2 32 | it 'should eval let a=1 then let a = 2 then a+a', -> 33 | expect(evaltj("let a=1 then let a = 2 then a+a")).to.equal 4 34 | 35 | describe "eval 2", -> 36 | it 'should eval "a"', -> 37 | expect(evaltj('"a"')).to.equal 'a' 38 | -------------------------------------------------------------------------------- /test/testmodule.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | nit = -> 7 | 8 | path = require 'path' 9 | lib = '../lib/' 10 | {Parser} = require lib+'parser' 11 | {constant, isArray, str} = require lib+'parser/base' 12 | {} = require lib+'compiler/compile' 13 | taiji = require lib+'taiji' 14 | TaijiModule = require lib+'module' 15 | {realCode} = require lib+'utils' 16 | 17 | compile = (code) -> 18 | head = 'taiji language 0.1\n' 19 | realCode taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 20 | 21 | run = (code) -> 22 | head = 'taiji language 0.1\n' 23 | code = taiji.compile(head+code, taiji.rootModule, taiji.builtins, {}) 24 | str eval code 25 | 26 | describe "taiji module: ", -> 27 | describe "path: ", -> 28 | it '__dirname', -> 29 | expect(__dirname).to.match /test/ 30 | it '__filename', -> 31 | expect(__filename).to.match /test\\testmodule.js/ 32 | it 'process.cwd', -> 33 | expect(process.cwd()).to.match /taijilang/ 34 | it 'process.execPath', -> 35 | expect(process.execPath).to.match /nodejs\\node/ 36 | it 'process.execArgv', -> 37 | expect(process.execArgv).to.deep.equal [] 38 | it 'process.env', -> 39 | #console.log process.env 40 | expect(process.env['TAIJILANG_PATH']).to.match /taijilang/ 41 | expect(process.env['taijilang_path']).to.match /taijilang/ 42 | 43 | describe 'new module: ', -> 44 | taijiModule = new TaijiModule('f:\\taijilang\\lib\\taiji.tj', null) 45 | it 'new TaijiModule', -> 46 | expect(taijiModule.basePath).to.match /lib/ 47 | expect(str taijiModule.modulePaths).to.match /taiji-libraries/ 48 | it 'should findPath', -> 49 | childModule = new TaijiModule('f:\\taijilang\\samples\\hello.tj', taijiModule) 50 | expect(childModule.basePath).to.equal 'f:\\taijilang\\samples' 51 | expect(childModule.findPath('.\\sample.tj')).to.equal 'f:\\taijilang\\samples\\sample.tj' 52 | expect(childModule.findPath('html.tj')).to.equal 'f:\\taijilang\\taiji-libraries\\html.tj' 53 | 54 | describe 'include!', -> 55 | it 'include! "./hello.tj"', -> 56 | expect(run("include! '../samples/hello.tj'")).to.equal "hello taiji" 57 | -------------------------------------------------------------------------------- /test/testprotoconstructor.js: -------------------------------------------------------------------------------- 1 | var chai = require("chai"); 2 | var expect = chai.expect; 3 | var iit = it.only; 4 | var idescribe = describe.only; 5 | var ndescribe = function() {}; 6 | var lib = '../lib/'; 7 | var _ref = require(lib + 'utils'), str = _ref.str, extend = _ref.extend; 8 | var taiji = require(lib + 'taiji'); 9 | 10 | describe("prototype constructor: ", function() { 11 | it('should constructor and instanceof', function () { 12 | var A = function(){} 13 | var B = function(){} 14 | b = new B() 15 | expect(b.constructor).to.equal(B); 16 | expect(b instanceof B).to.be.ok 17 | }); 18 | it('should derived constructor and instanceof', function () { 19 | var A = function(){} 20 | var B = function(){} 21 | function ctor() { this.constructor = B; } 22 | ctor.prototype = A.prototype; 23 | B.prototype = new ctor; 24 | b = new B() 25 | expect(b.constructor).to.equal(B); 26 | expect(b instanceof B).to.be.ok 27 | expect(b instanceof A).to.be.ok 28 | }); 29 | it('should inherit without ctor', function () { 30 | var A = function(){} 31 | var B = function(){} 32 | B.prototype = A.prototype; 33 | b = new B() 34 | expect(b.constructor).to.not.equal(B); 35 | expect(b.constructor).to.equal(A); 36 | expect(b instanceof B).to.be.ok 37 | expect(b instanceof A).to.be.ok 38 | }); 39 | }); -------------------------------------------------------------------------------- /test/testshell.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | 6 | require('shelljs/global') 7 | 8 | describe "taiji shell command: ", -> 9 | describe "experiment with shelljs: ", -> 10 | it 'should pwd', -> 11 | x = pwd() 12 | expect(x).to.match /taijilang/ 13 | 14 | it 'should display node version', -> 15 | x = exec('node --version', {silent:true}).output 16 | expect(x).to.equal "v0.10.22\r\n" 17 | 18 | it 'should display taiji version', -> 19 | x = exec('node bin/taiji -v', {silent:true}).output 20 | expect(x).to.equal "taiji version 0.1.0\n" 21 | 22 | describe "parse: ", -> 23 | it 'should parse hello.tj', -> 24 | x = exec('node bin/taiji -o samples-js --parse samples/hello.tj', {silent:true}).output 25 | expect(x).to.equal "" 26 | 27 | describe "compile file: ", -> 28 | it 'should compile hello.tj', -> 29 | x = exec('node bin/taiji -o samples-js -c samples/hello.tj', {silent:true}).output 30 | expect(x).to.equal "" 31 | it 'should compile sample.tj', -> 32 | x = exec('node bin/taiji -o samples-js -c samples/sample.tj', {silent:true}).output 33 | expect(x).to.equal "" 34 | it 'should compile loop.tj', -> 35 | x = exec('node bin/taiji -o samples-js -c samples/loop.tj', {silent:true}).output 36 | expect(x).to.equal "" 37 | 38 | describe "run: ", -> 39 | it 'should run hello.tj', -> 40 | x = exec('node bin/taiji samples/hello.tj', {silent:true}).output 41 | expect(x).to.equal "hello taiji\n" 42 | it 'should run sample.tj', -> 43 | x = exec('node bin/taiji samples/sample.tj', {silent:true}).output 44 | expect(x).to.equal "1\n7\n77\n77\n2\n2 3\n2\n2\n1\n2\n" 45 | -------------------------------------------------------------------------------- /test/testutils.coffee: -------------------------------------------------------------------------------- 1 | chai = require("chai") 2 | expect = chai.expect 3 | iit = it.only 4 | idescribe = describe.only 5 | ndescribe = -> 6 | 7 | lib = '../lib/' 8 | {isTaiji, baseFileName} = utils = require lib+'utils' 9 | 10 | describe "utils.coffee: ", -> 11 | describe "isTaiji filename: ", -> 12 | it ' 1.tj', -> 13 | expect(isTaiji '1.tj').to.equal true 14 | it ' 1.taiji', -> 15 | expect(isTaiji '1.taiji').to.equal true 16 | it ' 1.TAIJI', -> 17 | expect(isTaiji '1.TAIJI').to.equal false 18 | it ' 1.taiji.json', -> 19 | expect(isTaiji '1.taiji.json').to.equal true 20 | it ' 1.tj.json', -> 21 | expect(isTaiji '1.tj.json').to.equal true 22 | 23 | describe " baseFileName: ", -> 24 | it ' 1.tj', -> 25 | expect(baseFileName '1.tj', true).to.equal '1' 26 | it ' x\\1.tj', -> 27 | expect(baseFileName 'x\\1.tj', true, true).to.equal '1' 28 | it ' 1.taiji', -> 29 | expect(baseFileName '1.taiji', true).to.equal '1' 30 | it ' x\\1.taiji', -> 31 | expect(baseFileName 'x\\1.taiji', true, true).to.equal '1' 32 | it ' x//1.taiji', -> 33 | expect(baseFileName 'x//1.taiji', true).to.equal '1' 34 | it ' 1.taiji.json', -> 35 | expect(baseFileName '1.taiji.json', true).to.equal '1' 36 | it ' 1.tj.json', -> 37 | expect(baseFileName '1.tj.json', true).to.equal '1' 38 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | todo: document 2 | todo: tutorial:interactive samples 3 | 4 | todo: test new preprocess operator 5 | # let, letrec!, letloop!, doWhere!, while, doWhile!, doUntil!, cFor!, forIn!, forOf!, forIn!!, forOf!! 6 | 7 | todo: assign optimization 8 | # ssaVar, const var, dummy var, etc 9 | 10 | todo: better parser builtins ?!, ?/, etc 11 | 12 | todo: remove "entity" utility function 13 | # method: everything is array, even number, string, identifier or symbol 14 | # ['num!', value], ['str', "some string"], ['symbol', 'console'], ['symbol', '+'], etc... 15 | # syntax information(cursor, line number, etc) is attachted to array 16 | 17 | todo: [x, y, z] @= value # all= at --> all? 18 | 19 | todo: dummy var: can be assigned, but can not be readed 20 | # useful for expressiveness and optimization 21 | # while optimization, assigned to dummy var will be removed. 22 | # e.g. dummy! _; [x..., _] = lst; [_, y...] = lst 23 | # f = (x, y, _) -> ... # parameter _ is treated as dummy var automatically 24 | 25 | todo: pattern match, e.g. 26 | f = pattern (1) -> 1; (n) -> n+f(n-1) 27 | f = pattern 28 | (1) -> 1 29 | (n) -> n+f(n-1) 30 | 31 | todo: source map 32 | # a complicateful, hard and task with too much work to do 33 | # coffee-script is my friend. 34 | 35 | ------------------------------------------------------------ 36 | done: add more preprocess operator 37 | # let, letrec!, letloop!, doWhere!, while, doWhile!, doUntil!, cFor!, forIn!, forOf!, forIn!!, forOf!! 38 | done: transform string to symbol by escaping it. e.g.: \"x...", \"...x", \"..." 39 | done: ":" at the end of line can replace 'then' 40 | done: embedded meta compilation: #call, by evaluating the embedded meta code while running 41 | done: refactor definition ->, =>, etc, now they produces [->, [params], oneStatement], instead of statement list 42 | done: \ lead symbol to escape it, e.g. \=, \+=, \>>, \/, etc, useful to write macros. 43 | done: ellipsis subscript: a[1..3]; b[1...4]; a[...], a[..], x = a[..5]; x = a[...5] 44 | done: range: a...b, a..b 45 | done: hash assign: {a, b, c} = x # {} of the left side of = is treated as hash 46 | done: macro for "for", do, etc 47 | # macro for for/c-style, do(as begin!) do/where, do/When and do/until is not necessary any more. 48 | # forIn!! and forOf!! is necessary still. 49 | done: class similar to coffee-script 50 | # things like super, construcotr(too long name, maybe I'll use :: = (...)->)done: (x, @y...) ->, (x, @y...) => 51 | done: convert javascript keyword to legal idenentifier (var name) 52 | done: refactor meta compilation; no -=>, ==> or macro, macro is just meta compilation 53 | -------------------------------------------------------------------------- 54 | done: release 0.1.0 55 | done: \-=> and,\-> and \=> becomes |-=> and, |-> and |=> 56 | done: \-> and \=> prevent wrap return around function body 57 | done: distinct -> and =>, in => this become _this, similar to coffee-script 58 | done: default parameter: fn = (x=1, y=2) -> 59 | done: ellipsis arguments for call, e.g. fn(a, x..., b, y..., z) 60 | done: construct list with ellipsis operator 61 | x = [x..., y..., z] 62 | done: destructive list assign 63 | [a, b] = x 64 | [a..., b] = x 65 | [a, b...] = x 66 | [a, b..., c] = x 67 | [x, y] = [1, 2] 68 | done:[] becomes list, {} becomes expression block, {. .} becomes hash 69 | done: @@outsideVariable = value 70 | done: modulization, i.e. use!, export!, include! for taiji 71 | done: better format for generated javascript code 72 | done: the robust and modularity of parser, once again 73 | done: x... ellipsis parameter for function: (a, x...), (a, x..., b), (x..., b) 74 | done: x... ellipsis parameter for macro: (a, x...), (a, x..., b), (x..., b) 75 | done: merge short simple statement to one line when generating code 76 | done: merge var and assign in on statements when generating code 77 | done: bin/taiji: compile files 78 | done: repl: lodoneup var in on environment 79 | done: let the parser becomes dynamic parser 80 | done: $clauseExpression as interpolated expression in string. 81 | done: parser: do-where, do-until, do-while 82 | done: compiler: convert: extern variable 83 | done: compiler: code generation: generate tdoneen 84 | done: space, line, indent block operator expression 85 | done: chain expression: now it is called compact expression 86 | done: unquote and unquote-splice: ^ ^& 87 | done: concatenated line 88 | done: interpolated string 89 | done: curve dictionary 90 | done: data bracket 91 | done: @ as this 92 | done: parser: class extends (x, y) 93 | done: var 94 | done: cFor!, forIn!, forOf! 95 | done: let-then 96 | 97 | ----------------------------------------------------------------- 98 | cancel: implement {assign! left right} and {augmentAssign! left op right} so that programmer can define macros more easily. 99 | # hack for =, += in the parser is error-prone. 100 | # after implementing escape symbol with \, this todo may be unnessary. 101 | 102 | cancel: may be [x y z] should directly produce [x, y, z], no list! is unshift to its front, and item in {} or other blocks should produces ['call!', x, [y, z]] 103 | # now -> ... produces [-> [] statement], instead of [-> [] [statement list]] 104 | 105 | --------------------------------------------------------------------------------