├── public ├── lib ├── jison ├── jison.js ├── style │ ├── aescrawl.eot │ ├── aescrawl.ttf │ ├── aescrawl.woff │ ├── sh_navy.min.css │ ├── style.css │ ├── sh_javascript.min.js │ ├── sh_main.min.js │ └── aescrawl.svg ├── demo.js ├── json2-min.js └── index.html ├── .gitmodules ├── test.js ├── Jack.tmbundle ├── info.plist ├── Preferences │ └── Comments.tmPreferences └── Syntaxes │ └── Jack.tmLanguage ├── Makefile ├── README.markdown ├── test.jack ├── control_flow.jack ├── data_types.jack └── lib ├── jack.js └── jack ├── grammar.js ├── generator.js └── lexer.js /public/lib: -------------------------------------------------------------------------------- 1 | ../lib -------------------------------------------------------------------------------- /public/jison: -------------------------------------------------------------------------------- 1 | ../jison/lib/jison -------------------------------------------------------------------------------- /public/jison.js: -------------------------------------------------------------------------------- 1 | ../jison/lib/jison.js -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jison"] 2 | path = jison 3 | url = https://github.com/zaach/jison.git 4 | -------------------------------------------------------------------------------- /public/style/aescrawl.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creationix/jack-old/HEAD/public/style/aescrawl.eot -------------------------------------------------------------------------------- /public/style/aescrawl.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creationix/jack-old/HEAD/public/style/aescrawl.ttf -------------------------------------------------------------------------------- /public/style/aescrawl.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creationix/jack-old/HEAD/public/style/aescrawl.woff -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | require.paths.unshift(__dirname + "/lib"); 2 | var Jack = require('jack').Jack; 3 | var Fs = require('fs'); 4 | 5 | Fs.readFile('control_flow.jack', 'utf8', function (err, code) { 6 | console.log(Jack.compile(code)); 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /Jack.tmbundle/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Jack 7 | uuid 8 | CD464DB4-46C6-4631-9838-54B43C925D83 9 | 10 | 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: single 2 | 3 | single: 4 | echo "// jack/lexer.js\n" > public/jack.js 5 | cat lib/jack/lexer.js >> public/jack.js 6 | echo "\n// jack/grammar.js\n" >> public/jack.js 7 | cat lib/jack/grammar.js >> public/jack.js 8 | echo "\n// jack/generator.js\n" >> public/jack.js 9 | cat lib/jack/generator.js >> public/jack.js 10 | echo "\n// jack.js\n" >> public/jack.js 11 | cat lib/jack.js >> public/jack.js 12 | 13 | # Requires that compiler.jar be in the parent directory. 14 | # See google closure for details 15 | compressed: single 16 | java -jar ../compiler.jar --js public/jack.js -js_output_file public/jack-min.js 17 | 18 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Jack - Making programming playful 2 | 3 | Jack is a new language in development that gets translated to pure JavaScript and runs on top of nodeJS. 4 | 5 | ## Ideals 6 | 7 | - Be Simple! This is very important 8 | - Be fun! Otherwise, what's the point 9 | - Be productive! We can only really make time for this is something good comes out of it. 10 | 11 | ## Technical ideas 12 | 13 | - Compile cleanly down to JavaScript. 14 | - Use real prototypical inheritance, not the hacked version that made it into JavaScript. 15 | - Use real whitespace rules and get rid of those semicolons and braces. 16 | - Create a clean syntax for defining variables, objects and functions/blocks. That should be all that's needed. 17 | - Not allow fuzzy things like implicit globals and type coercion. 18 | - Implement a real compiler with some static analysis, not just regular expression hacks. 19 | - Unit tests all the way! 20 | 21 | ## Sample 22 | 23 | -------------------------------------------------------------------------------- /Jack.tmbundle/Preferences/Comments.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Comments 7 | scope 8 | source.jack 9 | settings 10 | 11 | shellVariables 12 | 13 | 14 | name 15 | TM_COMMENT_START 16 | value 17 | # 18 | 19 | 20 | name 21 | TM_COMMENT_START_2 22 | value 23 | /* 24 | 25 | 26 | name 27 | TM_COMMENT_END_2 28 | value 29 | */ 30 | 31 | 32 | 33 | uuid 34 | 47512F6D-BE9A-4B1D-BDBA-7F8C6A476AA9 35 | 36 | 37 | -------------------------------------------------------------------------------- /test.jack: -------------------------------------------------------------------------------- 1 | # Assignment: 2 | number = 42 3 | opposite_day = true 4 | 5 | # Conditions: 6 | if opposite_day 7 | number = -42 8 | end 9 | 10 | # Functions: 11 | square = fun x -> /x * x/g 12 | curry = fun a -> fun b -> "$a + $b" 13 | # Arrays: 14 | list = [1, 2, 3, 4, 5] 15 | 16 | # Objects: 17 | math = { 18 | root = Math 19 | square = square 20 | cube = fun x -> true 21 | } 22 | 23 | # Heredoc 24 | message = ''' 25 | Several lines 26 | that can be 27 | indented. 28 | ''' 29 | 30 | # Block functions: 31 | race = fun winner, runners -> 32 | winner 33 | runners 34 | end 35 | 36 | # Inherited Objects 37 | Animal = {legs=4 eyes=2} 38 | Insect = {Animal legs=6} 39 | Enumerable = {Array 40 | each = fun -> "Not implemented" 41 | reduce = fun -> 'Not implemented' 42 | } 43 | 44 | # Inherited Arrays 45 | [Enumerable 1,2,3,4,5] 46 | 47 | # Interpolated Strings 48 | # Based on an idea from Google's caja project 49 | # http://bit.ly/4irVV1 50 | "Hello $name" 51 | HTML""" 52 | 53 | 54 | $title 55 | 56 | 57 | ... 58 | 59 | 60 | """ 61 | JSON"{items: ${items.length}}" 62 | 63 | -------------------------------------------------------------------------------- /control_flow.jack: -------------------------------------------------------------------------------- 1 | # Assignment 2 | language = "Jack" 3 | cool = ok 4 | Animal = {legs=4 eyes=2} 5 | 6 | # Loops over objects/arrays 7 | for key, value in myObj if true 8 | # ... 9 | end 10 | # Compiles to: 11 | # 12 | # var key, value; 13 | # for (key in myObj) { 14 | # if (myObj.hasOwnProperty(key) && true) { 15 | # value = myObj[key]; 16 | # # ... 17 | # } 18 | # } 19 | 20 | # Array comprehensions 21 | [item for item in myList if item] 22 | # Compiles to: 23 | # myList.filter(function (item) { 24 | # return item; 25 | # }).map(function (item) { 26 | # return item; 27 | # }); 28 | 29 | # Object comprehensions 30 | {value for key, value in myObj unless value.length < 2} 31 | # Compiles to: 32 | # 33 | # Object.comprehension(myObj, function(key, value) { 34 | # return value; 35 | # }, function (key, value) { 36 | # return key.length < 2 37 | # }); 38 | # 39 | # OR: 40 | # 41 | # (function () { 42 | # var newobj = {}, key, value; 43 | # for (key in myObj) { 44 | # value = myObj[key]; 45 | # if (myObj.hasOwnProperty(key) && !(key.length < 2)) { 46 | # newobj[key] = value; 47 | # } 48 | # } 49 | # return newobj; 50 | # }()); 51 | 52 | 53 | # Long test 54 | long = {one=1 two=2 three=3 four=4 five=5 six=6 seven=7 eight=8 nine=9 ten=10} 55 | [ 56 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] 57 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] 58 | [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] 59 | ] 60 | [1,2,3,4,5] 61 | 62 | # Postfix conditionals 63 | do = ok if false 64 | do = no unless true 65 | 66 | # Conditionals 67 | if strange_stuff 68 | Octocat = {Animal legs=8} 69 | else 70 | Cat = {Animal} 71 | end 72 | 73 | # Inverse conditional 74 | unless opposite_day 75 | day = false 76 | end 77 | 78 | square = fun x -> 79 | x = true 80 | Cat = false 81 | newvar = no 82 | end -------------------------------------------------------------------------------- /public/style/sh_navy.min.css: -------------------------------------------------------------------------------- 1 | pre.sh_sourceCode{background-color:#000035;color:#008bff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_keyword{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_type{color:#e1e72f;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_string{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_regexp{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_specialchar{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_comment{color:#fb0;font-weight:normal;font-style:italic;}pre.sh_sourceCode .sh_number{color:#f87ff4;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_preproc{color:#b0f;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_symbol{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_function{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_cbracket{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_url{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_date{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_time{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_file{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_ip{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_name{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_variable{color:#13d8ef;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_oldfile{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_newfile{color:#fff;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_difflines{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_selector{color:#13d8ef;font-weight:normal;font-style:normal;}pre.sh_sourceCode .sh_property{color:#f8c50b;font-weight:bold;font-style:normal;}pre.sh_sourceCode .sh_value{color:#fff;font-weight:normal;font-style:normal;} -------------------------------------------------------------------------------- /public/demo.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var compile, onChange, output, real_compile, setOutput, source, status, timer; 3 | source = null; 4 | output = null; 5 | status = null; 6 | setOutput = function setOutput(js) { 7 | // Remove the contents 8 | while (output.firstChild) { 9 | output.removeChild(output.firstChild); 10 | } 11 | // put in new contents 12 | return output.appendChild(document.createTextNode(js)); 13 | }; 14 | real_compile = function real_compile() { 15 | var code, js; 16 | code = source.value; 17 | try { 18 | js = Jack.compile(code); 19 | setOutput(js); 20 | sh_highlightDocument(); 21 | } catch (e) { 22 | setOutput(e.stack); 23 | } 24 | return status.style.display = "none"; 25 | }; 26 | // Called 27 | compile = function compile() { 28 | status.style.display = "block"; 29 | return setTimeout(real_compile, 0); 30 | }; 31 | // Recompile after 500ms of idle time after any activity. 32 | timer = null; 33 | onChange = function onChange(e) { 34 | if (timer) { 35 | clearTimeout(timer); 36 | } 37 | return timer = setTimeout(compile, 500); 38 | }; 39 | // Wait for the dom to be built before moving on. 40 | this.onload = function onload() { 41 | var sample; 42 | // Store references to our textareas. 43 | source = document.getElementById("source"); 44 | output = document.getElementById("output"); 45 | status = document.getElementById("status"); 46 | // Load the sample code out of the script tag in the head. 47 | sample = document.getElementById("sample").innerHTML; 48 | sample = sample.substr(1, sample.length); 49 | // Fill in the box with the input and call compile 50 | source.value = sample; 51 | compile(); 52 | source.focus(); 53 | // Bind onkeyup and onchange in the text field 54 | source.addEventListener('keyup', onChange, false); 55 | return source.addEventListener('change', onChange, false); 56 | }; 57 | })(); 58 | -------------------------------------------------------------------------------- /data_types.jack: -------------------------------------------------------------------------------- 1 | # Boolean Literals 2 | # (Superset of JavaScript) 3 | true 4 | false 5 | on 6 | off 7 | yes 8 | no 9 | 10 | # Number Literals 11 | # (Same as JavaScript) 12 | 0xff0088 13 | 523 14 | 0XFFEE33 15 | 123.32 16 | -0.32 17 | 0.234 18 | 6.02e23 19 | 6.02E23 20 | 21 | # String Literals 22 | # Single quote only, but with heredoc style added 23 | # Heredoc contents don't include opening line and 24 | # are left trimmed to match closing triplet. 25 | 'Hello \'World\'' 26 | ''' 27 | Hello "World" 28 | In 'Multi' lines 29 | ''' 30 | 31 | # Interpolated literals 32 | # Double quotes and double heredoc 33 | # Values are replaced last minute by a smart agent. 34 | # (SQL escaper, HTML escape) 35 | "Hello $planetoid" 36 | SQL""" 37 | SELECT * FROM users 38 | WHERE name = $name 39 | """ 40 | HTML"$title" 41 | 42 | # http://google-caja.googlecode.com/svn/changes/mikesamuel/string-interpolation-29-Jan-2008/trunk/src/js/com/google/caja/interp/index.html 43 | # Interpolated use cases 44 | "$noun :verb" 45 | #-> String.interpolate(noun, " ", verb) 46 | #=> "World Greets" 47 | 48 | SQL"SELECT * FROM users WHERE name=$name" 49 | #-> SQL.interpolate("SELECT * FROM users WHERE name=", name) 50 | #=> "SELECT * FROM users WHERE name='O''Connor'" 51 | 52 | JSON"{name: ${data.name}, age: ${data.age}" 53 | #-> JSON.interpolate("{name: ", name, ", data.age: ", data.age}") 54 | #=> "{name: "Tim", age: 27}" 55 | 56 | # Regular Expression literals 57 | /123/g 58 | /^([^a-z]+)$/i 59 | 60 | # List Literals 61 | [ 1, 2, 3, 4 ] 62 | [ 63 | 1,0,0 64 | 0,1,0 65 | 0,0,1 66 | ] 67 | 68 | # Object Literals 69 | {name="Tim" age=27} 70 | { 71 | name="Tim" 72 | age=27 73 | } 74 | 75 | # Delegated Objects 76 | # Creates a new object that inherits from the given 77 | # prototype, and then overrides some properties. 78 | {Animal name="George" color="Brown"} 79 | {Animal 80 | name="George" 81 | color="Brown" 82 | } 83 | 84 | # Delegated Lists 85 | # Creates a clone of the passed in List-like object 86 | # but replaces the contents with that given. 87 | [HTMLColors 0x000000, 0xff8800, 0x0088ff, 0x887788] 88 | [HTMLColors 89 | 0x000000 90 | 0xff8800 91 | 0x0088ff 92 | 0x887788 93 | ] 94 | 95 | # Function literal 96 | fun x -> true 97 | # Block Function 98 | fun x, y -> 99 | x 100 | y 101 | end -------------------------------------------------------------------------------- /lib/jack.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var root = (typeof exports !== "undefined" && exports) || this, 3 | Jack = root.Jack || (root.Jack = {}); 4 | Jack.tokenize || (Jack.tokenize = require('jack/lexer').Jack.tokenize); 5 | Jack.parse || (Jack.parse = require('jack/grammar').Jack.parse); 6 | Jack.generate || (Jack.generate = require('jack/generator').Jack.generate); 7 | Jack.compile = function (code) { 8 | var tokens, tree, js; 9 | try { 10 | tokens = Jack.tokenize(code); 11 | tree = Jack.parse(tokens); 12 | js = Jack.generate(tree); 13 | return js; 14 | } catch (e) { 15 | var message, num, token, 16 | before, after, token_before, token_after; 17 | 18 | // Split the jison error message. 19 | message = e.message.split("\n"); 20 | num = parseInt(message[1]) - 1; 21 | message = message[0]; 22 | 23 | if (tokens) { 24 | if (token = tokens[num]) { 25 | before = code.substr(0, token.offset).match(/\n?.*$/)[0]; 26 | after = code.substr(token.offset, code.length).match(/^.*\n?/)[0]; 27 | token_before = tokens.slice(0, num).filter(function (other_token) { 28 | return other_token.lineno == token.lineno; 29 | }).map(function (other_token) { 30 | return other_token.name; 31 | }); 32 | token_after = tokens.slice(num).filter(function (other_token) { 33 | return other_token.lineno == token.lineno; 34 | }).map(function (other_token) { 35 | return other_token.name; 36 | }); 37 | e.message = message + 38 | " but found '" + token.name + "'\n" + 39 | "Line " + token.lineno + ": " + JSON.stringify(before) + " !! " + JSON.stringify(after) + "'\n" + 40 | "Tokens " + JSON.stringify(token_before) + " !! " + JSON.stringify(token_after); 41 | } 42 | } else { 43 | before = code.substr(0, num).match(/\n?.*$/)[0]; 44 | after = code.substr(num, code.length).match(/^.*\n?/)[0]; 45 | line_no = code.substr(0, num).split("\n").length; 46 | e.message = message + "\n" + 47 | "Line " + line_no + ": " + JSON.stringify(before) + " !! " + JSON.stringify(after); 48 | } 49 | throw e; 50 | } 51 | }; 52 | 53 | }()); 54 | if (typeof window !== "undefined" && typeof exports !== "undefined") { 55 | window.Jack = exports.Jack; 56 | } 57 | -------------------------------------------------------------------------------- /public/json2-min.js: -------------------------------------------------------------------------------- 1 | if(!this.JSON)this.JSON={}; 2 | (function(){function k(a){return a<10?"0"+a:a}function n(a){o.lastIndex=0;return o.test(a)?'"'+a.replace(o,function(c){var d=q[c];return typeof d==="string"?d:"\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,c){var d,f,i=g,e,b=c[a];if(b&&typeof b==="object"&&typeof b.toJSON==="function")b=b.toJSON(a);if(typeof j==="function")b=j.call(c,a,b);switch(typeof b){case "string":return n(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b); 3 | case "object":if(!b)return"null";g+=m;e=[];if(Object.prototype.toString.apply(b)==="[object Array]"){f=b.length;for(a=0;a|\|/g,"sh_symbol",-1],[/\{|\}/g,"sh_cbracket",-1],[/\b(?:Math|Infinity|NaN|undefined|arguments)\b/g,"sh_predef_var",-1],[/\b(?:Array|Boolean|Date|Error|EvalError|Function|Number|Object|RangeError|ReferenceError|RegExp|String|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt)\b/g,"sh_predef_func",-1],[/(?:[A-Za-z]|_)[A-Za-z0-9_]*(?=[ \t]*\()/g,"sh_function",-1]],[[/$/g,null,-2],[/(?:?)|(?:?)/g,"sh_url",-1],[/<\?xml/g,"sh_preproc",2,1],[//g,"sh_keyword",-1],[/<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,"sh_keyword",6,1],[/&(?:[A-Za-z0-9]+);/g,"sh_preproc",-1],[/<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,"sh_keyword",-1],[/<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,"sh_keyword",6,1],[/@[A-Za-z]+/g,"sh_type",-1],[/(?:TODO|FIXME|BUG)(?:[:]?)/g,"sh_todo",-1]],[[/\?>/g,"sh_preproc",-2],[/([^=" \t>]+)([ \t]*)(=?)/g,["sh_type","sh_normal","sh_symbol"],-1],[/"/g,"sh_string",3]],[[/\\(?:\\|")/g,null,-1],[/"/g,"sh_string",-2]],[[/>/g,"sh_preproc",-2],[/([^=" \t>]+)([ \t]*)(=?)/g,["sh_type","sh_normal","sh_symbol"],-1],[/"/g,"sh_string",3]],[[/-->/g,"sh_comment",-2],[/