├── .gitignore ├── .npmignore ├── 5.js ├── 6.js ├── LICENSE ├── README.md ├── bin ├── bootstrap ├── bootstrap_earl ├── earl ├── earl5 └── refresh ├── bootstrap ├── README ├── earl-grey.js ├── evaluator.js ├── expand.js ├── lex.js ├── location.js ├── macros │ ├── async.js │ ├── consts.js │ ├── core.js │ ├── helpers.js │ ├── logic.js │ ├── loop.js │ ├── macrodef.js │ ├── misc.js │ ├── modularity.js │ ├── operators.js │ ├── quote.js │ └── regexp.js ├── opt.js ├── parse.js ├── pattern.js ├── pp.js ├── register.js ├── run.js ├── stdenv.js ├── translate-js.js ├── util.js └── version.js ├── examples ├── bottle.eg ├── even.eg ├── fact.eg ├── fib.eg ├── macros.eg ├── operators.eg └── statemachine.eg ├── package.json ├── register.js ├── src ├── README ├── earl-grey.eg ├── evaluator.eg ├── expand.eg ├── lex.eg ├── location.eg ├── macros │ ├── async.eg │ ├── consts.eg │ ├── core.eg │ ├── helpers.eg │ ├── logic.eg │ ├── loop.eg │ ├── macrodef.eg │ ├── misc.eg │ ├── modularity.eg │ ├── operators.eg │ ├── quote.eg │ └── regexp.eg ├── opt.eg ├── parse.eg ├── pattern.eg ├── pp.eg ├── register.eg ├── run.eg ├── stdenv.eg ├── translate-js.eg ├── util.eg └── version.eg ├── test ├── feature_test.eg ├── macros.eg ├── mocha.opts ├── test-deconstruct.eg ├── test-globals.eg └── test-macros.eg └── todo.q /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.map 3 | lib5 4 | lib6 5 | node_modules 6 | junk 7 | egcache 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | junk 4 | egcache 5 | -------------------------------------------------------------------------------- /5.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require("./lib5/earl-grey.js"); 3 | -------------------------------------------------------------------------------- /6.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require("./lib6/earl-grey.js"); 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2014, Olivier Breuleux 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Earl Grey 3 | ========= 4 | 5 | [![Join the chat at https://gitter.im/breuleux/earl-grey](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/breuleux/earl-grey?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | 7 | Earl Grey ([website](http://earl-grey.io)) is a new 8 | language that compiles to JavaScript (ES6). Here's a quick rundown of 9 | its amazing features: 10 | 11 | * Python-like syntax 12 | * Fully compatible with the node.js ecosystem 13 | * Generators and async/await (no callback hell!) 14 | * Powerful, deeply integrated pattern matching 15 | * Used for assignment, function declaration, looping, exceptions... 16 | * A DOM-building DSL with customizable behavior 17 | * A very powerful hygienic macro system! 18 | * Define your own control structures or DSLs 19 | * Macros integrate seamlessly with the language 20 | * Macro libraries! Test with 21 | [earl-mocha](https://github.com/breuleux/earl-mocha), 22 | build with [earl-gulp](https://github.com/breuleux/earl-gulp), 23 | make dynamic pages with 24 | [earl-react](https://github.com/breuleux/earl-react), etc. 25 | * And much more! 26 | 27 | 28 | Resources 29 | --------- 30 | 31 | * [Website](http://earl-grey.io/) 32 | * [Installation instructions](http://earl-grey.io/use.html) 33 | * [Documentation](http://earl-grey.io/doc.html) 34 | * [Editor support](http://earl-grey.io/tooling.html) 35 | * [Contributing](http://earl-grey.io/contrib.html) 36 | * [Try it here!](http://earl-grey.io/repl.html) 37 | 38 | 39 | Examples 40 | -------- 41 | 42 | Counting all words in a block of test. Note that `count-words` is a 43 | variable name, not a subtraction (it is equivalent to the name 44 | `countWords`, if that's the notation you prefer). 45 | 46 | count-words(text) = 47 | counts = new Map() 48 | words = text.split(R"\W+") 49 | words each word -> 50 | current-count = counts.get(word) or 0 51 | counts.set(word, current-count + 1) 52 | consume(counts.entries()).sort(compare) where 53 | compare({w1, c1}, {w2, c2}) = c2 - c1 54 | 55 | `{x, y, ...}` is the notation for arrays in Earl Grey. Objects are 56 | denoted `{field = value, field2 = value2, ...}` 57 | 58 | **Generators**: the following defines a generator for the Fibonacci 59 | sequence and then prints all the even Fibonacci numbers less than 60 | 100. It shows off a little bit of everything: 61 | 62 | gen fib() = 63 | var {a, b} = {0, 1} 64 | while true: 65 | yield a 66 | {a, b} = {b, a + b} 67 | 68 | fib() each 69 | > 100 -> 70 | break 71 | n when n mod 2 == 0 -> 72 | print n 73 | 74 | The `each` operator accepts multiple clauses, which makes it especially 75 | easy to work on heterogenous arrays. 76 | 77 | 78 | **Asynchronous**: EG has `async` and `await` keywords to facilitate 79 | asynchronous programming, all based on Promises. Existing 80 | callback-based functionality can be converted to Promises using 81 | `promisify`: 82 | 83 | require: request 84 | g = promisify(request.get) 85 | 86 | async getXKCD(n = "") = 87 | response = await g('http://xkcd.com/{n}/info.0.json') 88 | JSON.parse(response.body) 89 | 90 | async: 91 | requests = await all 1..10 each i -> getXKCD(i) 92 | requests each req -> print req.alt 93 | 94 | 95 | **Classes**: 96 | 97 | class Person: 98 | constructor(name, age) = 99 | @name = name 100 | @age = age 101 | advance-inexorably-towards-death(n > 0 = 1) = 102 | @age += n 103 | say-name() = 104 | print 'Hello! My name is {@name}!' 105 | 106 | alice = Person("alice", 25) 107 | 108 | 109 | **Pattern matching** acts like a better `switch` or `case` 110 | statement. It can match values, types, extract values from arrays or 111 | objects, etc. 112 | 113 | match thing: 114 | 0 -> 115 | print "The thing is zero" 116 | < 0 -> 117 | print "The thing is negative" 118 | R"hello (.*)"? x -> 119 | ;; note: R"..." is a regular expression 120 | print 'The thing is saying hello' 121 | Number? x or String? x -> 122 | print "The thing is a number or a string" 123 | {x, y, z} -> 124 | print 'The thing is an array of three things, {x}, {y} and {z}' 125 | {=> name} -> 126 | print 'The thing has a "name" field' 127 | else -> 128 | print "I don't know what the thing is!" 129 | 130 | 131 | -------------------------------------------------------------------------------- /bin/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | fs = require("fs"); 4 | var r = require("../bootstrap/run"); 5 | 6 | if (process.argv[2] === "-5" || process.argv[2] === "-6") { 7 | var version = process.argv[2]; 8 | var arg = process.argv[3]; 9 | } 10 | else { 11 | var version = "-6"; 12 | var arg = process.argv[2]; 13 | } 14 | 15 | var n = parseFloat(arg || 0); 16 | var opts = version + "rvso"; 17 | var endpoint = "lib" + version[1]; 18 | 19 | console.log("Options:", opts); 20 | console.log("Bootstrap into:", endpoint, "after", n, "iterations."); 21 | 22 | function rmrf(path) { 23 | if(fs.existsSync(path)) { 24 | fs.readdirSync(path).forEach(function(file, index) { 25 | var curPath = path + "/" + file; 26 | if(fs.lstatSync(curPath).isDirectory()) { 27 | rmrf(curPath); 28 | } else { 29 | fs.unlinkSync(curPath); 30 | } 31 | }); 32 | fs.rmdirSync(path); 33 | } 34 | } 35 | 36 | var i = 0; 37 | var name = i == n ? endpoint : "temp_bootstrap_" + i; 38 | console.log("Making", name) 39 | r.run(["compile", opts, name, "src"]); 40 | while (i < n) { 41 | r = require("../" + name + "/run"); 42 | i++; 43 | name = i == n ? endpoint : "temp_bootstrap_" + i; 44 | console.log("Making", name) 45 | r.run(["compile", opts, name, "src"]); 46 | } 47 | 48 | for (var i = 0; i < n; i++) { 49 | name = "temp_bootstrap_" + i; 50 | console.log("rm " + name); 51 | rmrf(name); 52 | } 53 | 54 | console.log("done") 55 | -------------------------------------------------------------------------------- /bin/bootstrap_earl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | r = require("../bootstrap/run.js") 4 | r.run(process.argv.slice(2)) 5 | -------------------------------------------------------------------------------- /bin/earl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("source-map-support").install(); 4 | r = require("../lib6/run"); 5 | r.run(process.argv.slice(2)); 6 | -------------------------------------------------------------------------------- /bin/earl5: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("source-map-support").install(); 4 | r = require("../lib5/run"); 5 | r.run(process.argv.slice(2)); 6 | -------------------------------------------------------------------------------- /bin/refresh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | fs = require("fs"); 4 | var r = require("../bootstrap/run"); 5 | 6 | function rmrf(path) { 7 | if(fs.existsSync(path)) { 8 | fs.readdirSync(path).forEach(function(file, index) { 9 | var curPath = path + "/" + file; 10 | if(fs.lstatSync(curPath).isDirectory()) { 11 | rmrf(curPath); 12 | } else { 13 | fs.unlinkSync(curPath); 14 | } 15 | }); 16 | fs.rmdirSync(path); 17 | } 18 | } 19 | 20 | var version = process.argv[2] || "-6" 21 | var name = "lib" + version[1]; 22 | var opts = version + "vso"; 23 | 24 | console.log("Making", name); 25 | r.run(["compile", opts, name, "src"]); 26 | console.log("done"); 27 | -------------------------------------------------------------------------------- /bootstrap/README: -------------------------------------------------------------------------------- 1 | 2 | Source code organization 3 | ------------------------ 4 | 5 | location.eg 6 | Defines the Source and Location classes and a bunch of utility 7 | functions for highlighting. 8 | 9 | lex.eg 10 | Defines the lexer. 11 | lex.tokenize{Source} ==> list of tokens 12 | 13 | parse.eg 14 | Operator precedence parsing. 15 | Note that the following simplifications are applied in this phase: 16 | * "a with b" ==> a{b} 17 | * "foo bar: baz" ==> foo{bar, baz} 18 | parse.parse{tokens} ==> raw AST (unexpanded) 19 | 20 | expand.eg 21 | Defines the Scope, Env and Expander classes, which are the basis of 22 | the macro expander. Core behavior like symbol resolution and 23 | expansion of #multi and #data nodes are here. 24 | 25 | stdenv.eg 26 | Defines most core macros and control structures. 27 | * if, while, break, class, each, etc. 28 | * Whitelist of global variables. 29 | * Contains the code for a few required shims (e.g. Array.prototype["::check"]) 30 | 31 | pattern.eg 32 | Most of the code pertaining to pattern matching is here. 33 | 34 | translate-js.eg 35 | Defines Translator, which takes an expanded AST and produces 36 | JavaScript code. 37 | 38 | earl-grey.eg 39 | Glues all the parts together in a coherent interface, Generator. 40 | 41 | run.eg 42 | Defines the command-line interface of the earl utility. 43 | Entry point is the run function. 44 | 45 | register.eg 46 | Import to register earl grey as an extension. 47 | 48 | 49 | util.eg 50 | Miscellaneous utilities. 51 | 52 | opt.eg 53 | Defines the hoist function, a minor optimization. 54 | 55 | pp.eg 56 | Pretty-printing, to be removed (probably). 57 | 58 | 59 | Notes 60 | ----- 61 | 62 | AST nodes are plain arrays, so you won't find a formal definition 63 | anywhere. Essentially: 64 | 65 | Core nodes (produced by parse.parse): 66 | #symbol{String?} ==> symbol 67 | #value{v} ==> literals (numbers, strings, etc.) 68 | #multi{...} ==> [a, b, ...] (at least two elements in []s) 69 | #data{...} ==> {...} 70 | #send{obj, msg} ==> function calls, field accesses, etc. 71 | 72 | Processed nodes (produced during macro expansion in addition to core nodes): 73 | #array{...} ==> create an array 74 | #object{#array{k1, v1}, ...} ==> create an object from key/value pairs 75 | #if{test, x, y} ==> conditionals 76 | #scope{vars, body} ==> variable declaration 77 | #lambda{args, body} ==> function definition 78 | #js_while, #js_for, etc. ==> javascript-specific control structures 79 | 80 | Temporary nodes/expansion control 81 | #macro{fn} ==> `fn` will be used to expand #send{#macro{fn}, arg} 82 | #nostep{macro} ==> Defer macro expansion to later 83 | (macro expansion may happen in multiple contexts) 84 | #parse{str, url} ==> Instruct EG's expander to parse the code string 85 | (useful to implement interpolation in strings) 86 | -------------------------------------------------------------------------------- /bootstrap/evaluator.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let module$0;let path$0;let vm$0;let evaluator$0;module$0=require("module");path$0=require("path");vm$0=require("vm");evaluator$0=(function evaluator(options$0){let g$0;let m$1$0;let gl$0;let $targ$0;let g$1;let m$0$0;let accum$0;let paths$0;let e_module$0;let e_require$0;let setup$0;let __eval$0;let req$0;let glob$0;req$0=require;if(options$0.globvar){m$0$0=send(global,options$0.globvar);if((m$0$0===(void 0))){m$1$0=options$0.global;if((m$1$0===true)){gl$0=global;}else{if(getChecker(Object)(m$1$0)){g$0=m$1$0;gl$0=g$0;}else{gl$0=Object.create(global);}}$targ$0=gl$0;(global[options$0.globvar]=$targ$0);glob$0=gl$0;}else{g$1=m$0$0;glob$0=g$1;}}else{glob$0=global;}if(module$0._nodeModulePaths){if(options$0.cwd){paths$0=module$0._nodeModulePaths(options$0.cwd);}else{paths$0=[];}e_module$0=(new module$0(options$0.showname));__amp____colon__(e_module$0,({"filename":options$0.filename,"paths":paths$0}));e_require$0=(function e_require(path$1){return module$0._load(path$1,e_module$0,true);});__amp____colon__(e_require$0,__amp____colon__(({"main":e_module$0}),__amp____colon__(((accum$0=({})),(accum$0["resolve"]=(function resolve(path$2){return module$0._resolveFileName(path$2,e_module$0);})),accum$0),({"paths":paths$0,"cache":req$0.cache}))));setup$0=({"__filename":options$0.filename,"__dirname":path$0.dirname(options$0.filename),"module":e_module$0,"require":e_require$0,"exports":({})});__amp____colon__(glob$0,setup$0);return (function(code$0){let script$0;let rval$0;script$0=vm$0.createScript(code$0,options$0.showname);rval$0=script$0.runInThisContext();return rval$0;});}else{__eval$0=eval;return (function(code$1){return __eval$0(code$1);});}});$targ$1=evaluator$0;(exports["evaluator"]=$targ$1);(void 0); 3 | //# sourceMappingURL=evaluator.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/location.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$3;let $targ$4;let $targ$5;let $targ$6;let $targ$7;let $targ$8;let $targ$9;let $targ$10;let $targ$11;let $0$0;let binsearch$0;let $1$0;let __lt____gt__$0;let _repr$0;let fs$0;let opg$0;let Source$0;let Location$0;let $2$0;let highlight$0;let highlight_locations$0;let merge_locations$0;let repr$0;let __lt____lt____colon__$0;let __plus____plus____colon__$0;let format_error$0;let display_error$0;$0$0=require("./util");binsearch$0=getProperty($0$0,"binsearch","./util");$1$0=require("./pp");__lt____gt__$0=getProperty($1$0,"<>","./pp");_repr$0=getProperty($1$0,"repr","./pp");fs$0=require("fs");opg$0=require("opg");Source$0=getProperty(opg$0,"Source","opg");Location$0=getProperty(opg$0,"Location","opg");$2$0=require("opg/lib/highlight");highlight$0=getProperty($2$0,"highlight","opg/lib/highlight");highlight_locations$0=getProperty($2$0,"highlightLocations","opg/lib/highlight");merge_locations$0=getProperty($2$0,"mergeLocations","opg/lib/highlight");repr$0=_repr$0;__lt____lt____colon__$0=(function(x$0,y$0){let $targ$1;let $targ$2;let $targ$0;if((!getChecker(Location$0)(x$0.location))){if(((!y$0)||getChecker(Location$0)(y$0))){$targ$0=y$0;}else{$targ$0=y$0.location;}(x$0["location"]=$targ$0);if(y$0.called){$targ$1=y$0.called;(x$0["called"]=$targ$1);(void 0);}if(y$0.name){$targ$2=y$0.name;(x$0["name"]=$targ$2);(void 0);}}return x$0;});__plus____plus____colon__$0=(function(x$1,y$1){let rval$0;let x2$0;let y2$0;if(((!x$1)||getChecker(Location$0)(x$1))){x2$0=x$1;}else{x2$0=x$1.location;}if(((!y$1)||getChecker(Location$0)(y$1))){y2$0=y$1;}else{y2$0=y$1.location;}rval$0=false;try{rval$0=merge_locations$0([x2$0,y2$0]);rval$0;}catch(excv$0){let e$0;e$0=excv$0;rval$0=undefined;rval$0;}return rval$0;});format_error$0=(function format_error(){let m$1;let acc$0;let temp$0;let hls$0;let locs$0;let rval$1;let loc$1;let data$0;let other$0;let url$0;let start$0;let end$0;let loc$0;let args$0;let fmt_args$0;let $$5475$0;let $$5476$0;let $$5477$0;let t0$1;let t1$1;let t2$0;let e$1;let ph$1$0;let context$0;let t0$0;let t1$0;let m$0$0;m$0$0=arguments;t0$0=m$0$0.length;if(((t0$0>=1)&&(t0$0<=2))){t1$0=m$0$0[0];e$1=t1$0;ph$1$0=t1$0;if((1>=t0$0)){context$0=0;}else{context$0=m$0$0[1];}fmt_args$0=(function fmt_args(e$2){if((e$2.args&&e$2.args.length)){return ENode([".error_args"],({}),repr$0(e$2.args));}else{return "";}});t0$1=ph$1$0;if((getChecker(ErrorFactory(["syntax"]))(t0$1)&&(___hasprop(t0$1,"args")&&((t1$1=t0$1.args),(Array.isArray(t1$1)&&((t2$0=t1$1.length),(t2$0===1))))))){args$0=t1$1[0];hls$0=["hl1","hl2","hl3","hl4"];acc$0=[];temp$0=null;m$1=null;$3:for(m$1 of enumerate(items(args$0))){let i$0;let key$0;let arg$0;let t0$2;let t1$2;let t2$1;let t3$0;t0$2=m$1;if((Array.isArray(t0$2)&&((t1$2=t0$2.length),((t1$2===2)&&((i$0=t0$2[0]),(t2$1=t0$2[1]),(Array.isArray(t2$1)&&((t3$0=t2$1.length),((t3$0===2)&&((key$0=t2$1[0]),(arg$0=t2$1[1]),(arg$0&&arg$0.location)))))))))){temp$0=[arg$0.location,send(hls$0,(i$0%4))];acc$0.push(temp$0);}else{false;}}locs$0=acc$0;return ENode(["div"],({}),[ENode([".error"],({}),[ENode([".error_type"],({}),e$1.name),ENode([".error_message"],({}),e$1.message)]),ENode([".error_args",".syntax"],({}),repr$0(args$0)),highlight_locations$0(locs$0,context$0)]);}else{if((($$5476$0=___hasprop(t0$1,"location"))&&((t1$1=t0$1.location),getChecker(Location$0)(t1$1)))){loc$0=t1$1;return ENode(["div"],({}),[ENode([".error"],({}),[ENode([".error_type"],({}),e$1.name),ENode([".error_message"],({}),e$1.message)]),fmt_args$0(e$1),highlight_locations$0([[loc$0,"hl1"]],context$0),ENode([".traceback"],({}),(e$1.stack||""))]);}else{if(($$5476$0&&(Array.isArray(t1$1)&&((t2$0=t1$1.length),((t2$0===4)&&(t1$1[0]==="location")))))){url$0=t1$1[1];start$0=t1$1[2];end$0=t1$1[3];rval$1=false;try{rval$1=fs$0.readFileSync(url$0,"utf8");rval$1;}catch(excv$1){let e$3;e$3=excv$1;rval$1=null;rval$1;}data$0=rval$1;if(data$0){loc$1=Location$0(Source$0(data$0,url$0),start$0,end$0);return ENode(["div"],({}),[ENode([".error"],({}),[ENode([".error_type"],({}),e$1.name),ENode([".error_message"],({}),e$1.message)]),fmt_args$0(e$1),highlight_locations$0([[loc$1,"hl1"]],context$0),ENode([".traceback"],({}),ENode([],({}),(e$1.stack||"")))]);}else{return ENode(["div"],({}),[ENode([".error"],({}),[ENode([".error_type"],({}),e$1.name),ENode([".error_message"],({}),e$1.message)]),fmt_args$0(e$1),ENode([".traceback"],({}),ENode([],({}),(e$1.stack||e$1)))]);}}else{other$0=ph$1$0;return ENode(["div"],({}),[ENode([".error"],({}),[ENode([".error_type"],({}),e$1.name),ENode([".error_message"],({}),e$1.message)]),fmt_args$0(e$1),ENode([".traceback"],({}),ENode([],({}),e$1.stack))]);}}}}else{return ___match_error(m$0$0,"{match e, context = 0}");}});display_error$0=(function display_error(e$4){return __lt____gt__$0(null,format_error$0(e$4));});$targ$3=Source$0;(exports["Source"]=$targ$3);$targ$4=Location$0;(exports["Location"]=$targ$4);$targ$5=highlight$0;(exports["highlight"]=$targ$5);$targ$6=highlight_locations$0;(exports["highlight_locations"]=$targ$6);$targ$7=merge_locations$0;(exports["merge_locations"]=$targ$7);$targ$8=__lt____lt____colon__$0;(exports["<<:"]=$targ$8);$targ$9=__plus____plus____colon__$0;(exports["++:"]=$targ$9);$targ$10=format_error$0;(exports["format_error"]=$targ$10);$targ$11=display_error$0;(exports["display_error"]=$targ$11);(void 0); 3 | //# sourceMappingURL=location.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/macros/consts.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let $targ$0;let $0$0;let protected_value$0;let value_mac$0;$0$0=require("./helpers");protected_value$0=getProperty($0$0,"protected_value","./helpers");value_mac$0=getProperty($0$0,"value_mac","./helpers");if((typeof(module)==="undefined")){$targ$1=undefined;(global["module"]=$targ$1);(void 0);}$targ$0=(function(mac$0,bind$0){let m$0;let m$1;let chk$0;let $targ$2;let accum$0;let chk$1;let $targ$3;let accum$1;let chk$2;let $targ$4;let accum$2;let chk$3;let $targ$5;let accum$3;let chk$4;let proj$0;let $targ$6;let accum$4;let chk$5;let proj$1;let $targ$7;let accum$5;let chk$6;let proj$2;let $targ$8;let accum$6;let chk$7;let proj$3;let $targ$9;let accum$7;let chk$8;let $targ$10;let accum$8;let m$2;let acc$0;let temp$0;let kv$0;let global_variables$0;let keywords$0;let exports$0;exports$0=({});global_variables$0=["!=","!==","&","&+","&:","*","+","++","-","--","/","<","<<","<=","==","===",">",">=",">>",">>>","^+","|+","___build_array","___extend","___hasprop","___js_fetch","___match_error","___node","___serialize_ast","__dirname","__filename","and","arguments","Array","ArrayBuffer","Buffer","clearImmediate","clearInterval","clearTimeout","clone","console","consume","contains","DataView","Date","decodeURI","decodeURIComponent","dir","encodeURI","encodeURIComponent","ENode","enumerate","equal","Error","ErrorFactory","eval","EvalError","exports","Float32Array","Float64Array","Function","getChecker","getProjector","getProperty","global","in","Infinity","instanceof","Int16Array","Int32Array","Int8Array","Intl","isFinite","isNaN","items","JSON","keys","Map","Math","mod","module","NaN","neighbours","nequal","not","Object","object","or","parseFloat","parseInt","predicate","process","product","Promise","promisify","Proxy","range","RangeError","ReferenceError","Reflect","RegExp","repr","send","Set","setImmediate","setInterval","setTimeout","spawn","Symbol","SyntaxError","take","this","TypeError","typeof","Uint16Array","Uint32Array","Uint8Array","Uint8ClampedArray","URIError","WeakMap","WeakSet","zip"];m$0=null;$1:for(m$0 of global_variables$0){let gvar$0;gvar$0=m$0;bind$0(gvar$0,__amp__(["variable",gvar$0],({"mutable":false,"assigned":true})));}keywords$0=({"true":protected_value$0("true",true),"false":protected_value$0("false",false),"null":protected_value$0("null",null),"undefined":protected_value$0("undefined",undefined),"pass":["variable","undefined"]});m$1=null;$2:for(m$1 of items(keywords$0)){let gvar$1;let v$0;let t0$0;let t1$0;t0$0=m$1;if((Array.isArray(t0$0)&&((t1$0=t0$0.length),(t1$0===2)))){gvar$1=t0$0[0];v$0=t0$0[1];bind$0(gvar$1,v$0);}else{___match_error(m$1);}}kv$0=__amp____colon__((($targ$2=((chk$0=(function chk(x$0){return ["send",["symbol","==="],["data",x$0,["value",null]]];})),value_mac$0("null",chk$0))),(accum$0=({})),(accum$0["null"]=$targ$2),accum$0),__amp____colon__((($targ$3=((chk$1=(function chk(x$1){return ["send",["symbol","==="],["data",x$1,["value",undefined]]];})),value_mac$0("undefined",chk$1))),(accum$1=({})),(accum$1["undefined"]=$targ$3),accum$1),__amp____colon__((($targ$4=((chk$2=(function chk(x$2){return ["send",["symbol","if"],["data",x$2,["symbol","true"],["symbol","false"]]];})),value_mac$0("true",chk$2))),(accum$2=({})),(accum$2["true"]=$targ$4),accum$2),__amp____colon__((($targ$5=((chk$3=(function chk(x$3){return ["send",["symbol","not"],["data",["void"],x$3]];})),value_mac$0("false",chk$3))),(accum$3=({})),(accum$3["false"]=$targ$5),accum$3),__amp____colon__((($targ$6=((chk$4=(function chk(x$4){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$4]],["send",["symbol","."],["data",["void"],["symbol","string"]]]]];})),(proj$0=(function proj(x$5){return ["data",["symbol","true"],["send",["symbol","String"],["data",x$5]]];})),value_mac$0("String",chk$4,proj$0))),(accum$4=({})),(accum$4["String"]=$targ$6),accum$4),__amp____colon__((($targ$7=((chk$5=(function chk(x$6){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$6]],["send",["symbol","."],["data",["void"],["symbol","number"]]]]];})),(proj$1=(function proj(x$7){return ["data",["symbol","true"],["send",["symbol","parseFloat"],["data",x$7]]];})),value_mac$0("Number",chk$5,proj$1))),(accum$5=({})),(accum$5["Number"]=$targ$7),accum$5),__amp____colon__((($targ$8=((chk$6=(function chk(x$8){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$8]],["send",["symbol","."],["data",["void"],["symbol","boolean"]]]]];})),(proj$2=(function proj(x$9){return ["data",["symbol","true"],["send",["symbol","Boolean"],["data",x$9]]];})),value_mac$0("Boolean",chk$6,proj$2))),(accum$6=({})),(accum$6["Boolean"]=$targ$8),accum$6),__amp____colon__((($targ$9=((chk$7=(function chk(x$10){return ["send",["send",["symbol","Array"],["send",["symbol","."],["data",["void"],["symbol","isArray"]]]],["data",x$10]];})),(proj$3=(function proj(x$11){return ["data",["symbol","true"],["multi",["send",["symbol","="],["data",["symbol","t"],x$11]],["send",["symbol","if"],["data",["send",["send",["symbol","Array"],["send",["symbol","."],["data",["void"],["symbol","isArray"]]]],["data",["symbol","t"]]],["symbol","t"],["data",["symbol","t"]]]]]];})),value_mac$0("Array",chk$7,proj$3))),(accum$7=({})),(accum$7["Array"]=$targ$9),accum$7),(($targ$10=((chk$8=(function chk(x$12){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$12]],["send",["symbol","."],["data",["void"],["symbol","function"]]]]];})),value_mac$0("Function",chk$8))),(accum$8=({})),(accum$8["Function"]=$targ$10),accum$8)))))))));acc$0=[];temp$0=null;m$2=null;$3:for(m$2 of items(kv$0)){let k$0;let v$1;let t0$1;let t1$1;t0$1=m$2;if((Array.isArray(t0$1)&&((t1$1=t0$1.length),(t1$1===2)))){k$0=t0$1[0];v$1=t0$1[1];temp$0=mac$0(k$0)(v$1);acc$0.push(temp$0);}else{___match_error(m$2);}}return exports$0;});(module["exports"]=$targ$0);(void 0); 3 | //# sourceMappingURL=consts.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/macros/macrodef.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let $targ$0;let $0$0;let __lt____lt____colon__$0;let $1$0;let Env$0;let topscope$0;let $2$0;let ctx_mac$0;let expr_mac2$0;let multimacro$0;let inject__minus__tools$0;let $3$0;let camelCase$0;$0$0=require("../location");__lt____lt____colon__$0=getProperty($0$0,"<<:","../location");$1$0=require("../expand");Env$0=getProperty($1$0,"Env","../expand");topscope$0=getProperty($1$0,"topscope","../expand");$2$0=require("./helpers");ctx_mac$0=getProperty($2$0,"ctx_mac","./helpers");expr_mac2$0=getProperty($2$0,"expr_mac2","./helpers");multimacro$0=getProperty($2$0,"multimacro","./helpers");inject__minus__tools$0=getProperty($2$0,"injectTools","./helpers");$3$0=require("../util");camelCase$0=getProperty($3$0,"camelCase","../util");if((typeof(module)==="undefined")){$targ$1=undefined;(global["module"]=$targ$1);(void 0);}$targ$0=(function(mac$0){let t0$3;let t0$7;let t0$11;let mak$0;let t0$16;let wrap_macro$0;let wrap_macro_func$0;let $targ$2;let imacro_mac$0;let $targ$3;let icmacro_mac$0;let $targ$4;let macros_mac$0;let $targ$5;let macro_mac$0;let exports$0;exports$0=({});wrap_macro$0=(function wrap_macro(info$0,mac$1){let mac2$0;mac2$0=(function mac2(c$0,s$0,f$0,e$0){let bindings$0;let env$0;let $targ$6;let r$0;bindings$0=info$0.env.list_bindings(info$0.scope);env$0=Env$0();$targ$6=bindings$0;(env$0.scopes[topscope$0.name]=$targ$6);r$0=mac$1.call(info$0,c$0,s$0,f$0,e$0);return env$0.mark(r$0);});return ["macro",mac2$0];});wrap_macro_func$0=(function wrap_macro_func(info$1,args$0,body$0){let it$0;it$0=info$1.env.mark(["symbol","@"]);return ["send",["symbol","_lambda"],["data",args$0,["send",["symbol","="],["data",it$0,["symbol","this"]]],body$0,["value",null]]];});$targ$2=(function(context$0,info$2,form$0,ph$0$0){let t0$1;let t0$2;let mac$2;let s$1;let name$0;let sym$0;let arguments$1;let ast$0;let t0$0;let t1$0;let t2$0;let t3$0;let t4$0;let bridge$$13440$0;t0$0=ph$0$0;t1$0=t0$0.length;if(((t1$0===3)&&((t0$0[0]==="data")&&((t2$0=t0$0[1]),(Array.isArray(t2$0)&&((t3$0=t2$0.length),((t3$0===3)&&((t2$0[0]==="send")&&((t4$0=t2$0[1]),(name$0=t4$0),(bridge$$13440$0=t4$0),((Array.isArray(bridge$$13440$0)&&((t0$1=bridge$$13440$0.length),((t0$1===2)&&((bridge$$13440$0[0]==="symbol")&&((sym$0=bridge$$13440$0[1]),true)))))||(Array.isArray(bridge$$13440$0)&&((t0$2=bridge$$13440$0.length),((t0$2===2)&&((bridge$$13440$0[0]==="value")&&((sym$0=bridge$$13440$0[1]),true))))))))))))))){arguments$1=t2$0[2];ast$0=t0$0[2];mac$2=info$2.go(wrap_macro_func$0(info$2,arguments$1,ast$0),"parse","eval");s$1=__lt____lt____colon__$0(info$2.mark(__amp____colon__(["symbol",sym$0],({"env":name$0.env}))),name$0);return ["declare_raw",s$1,wrap_macro$0(info$2,expr_mac2$0(mac$2))];}else{return ___match_error(ph$0$0,"#data{#send{name and [#symbol{sym} or #value{sym}], arguments}, ast}");}});t0$3=getProjector(mac$0("inlineMacro"))($targ$2);if(t0$3[0]){imacro_mac$0=t0$3[1];}else{___match_error($targ$2,"mac{\"inlineMacro\"}! imacro_mac{context, info, form, match}");}$targ$3=(function(context$1,info$3,form$1,ph$1$0){let t0$5;let t0$6;let mac$3;let s$2;let name$1;let sym$1;let arguments$2;let ast$1;let t0$4;let t1$1;let t2$1;let t3$1;let t4$1;let bridge$$13512$0;t0$4=ph$1$0;t1$1=t0$4.length;if(((t1$1===3)&&((t0$4[0]==="data")&&((t2$1=t0$4[1]),(Array.isArray(t2$1)&&((t3$1=t2$1.length),((t3$1===3)&&((t2$1[0]==="send")&&((t4$1=t2$1[1]),(name$1=t4$1),(bridge$$13512$0=t4$1),((Array.isArray(bridge$$13512$0)&&((t0$5=bridge$$13512$0.length),((t0$5===2)&&((bridge$$13512$0[0]==="symbol")&&((sym$1=bridge$$13512$0[1]),true)))))||(Array.isArray(bridge$$13512$0)&&((t0$6=bridge$$13512$0.length),((t0$6===2)&&((bridge$$13512$0[0]==="value")&&((sym$1=bridge$$13512$0[1]),true))))))))))))))){arguments$2=t2$1[2];ast$1=t0$4[2];mac$3=info$3.go(wrap_macro_func$0(info$3,arguments$2,ast$1),"parse","eval");s$2=__lt____lt____colon__$0(info$3.mark(__amp____colon__(["symbol",sym$1],({"env":name$1.env}))),name$1);return ["declare_raw",s$2,wrap_macro$0(info$3,ctx_mac$0(mac$3))];}else{return ___match_error(ph$1$0,"#data{#send{name and [#symbol{sym} or #value{sym}], arguments}, ast}");}});t0$7=getProjector(mac$0("inlineCmacro"))($targ$3);if(t0$7[0]){icmacro_mac$0=t0$7[1];}else{___match_error($targ$3,"mac{\"inlineCmacro\"}! icmacro_mac{context, info, form, match}");}$targ$4=(function(context$2,info$4,temp$0$0,temp$1$0){let t0$8;let t0$9;let t1$2;let m$0;let acc$0;let temp$2;let macs$0;let the_macros$0;let form$2;let env$1;let body$1;t0$8=temp$0$0;form$2=t0$8;if(___hasprop(t0$8,"env")){env$1=t0$8.env;}else{___match_error(temp$0$0);}t0$9=temp$1$0;if((Array.isArray(t0$9)&&((t1$2=t0$9.length),((t1$2===2)&&(t0$9[0]==="data"))))){body$1=t0$9[1];}else{___match_error(temp$1$0);}the_macros$0=info$4.go(body$1,"parse","eval");acc$0=[];temp$2=null;m$0=null;$4:for(m$0 of items(the_macros$0)){let f$1;let k$0;let v$0;let t0$10;let t1$3;t0$10=m$0;if((Array.isArray(t0$10)&&((t1$3=t0$10.length),(t1$3===2)))){k$0=t0$10[0];v$0=t0$10[1];f$1=(function f(ctx$0,info$5,form$3,expr$0){return v$0.call(inject__minus__tools$0(info$5),expr$0);});temp$2=["declare_raw",__amp____colon__(["symbol",k$0],({"env":env$1})),["macro",f$1]];acc$0.push(temp$2);}else{___match_error(m$0);}}macs$0=acc$0;return ["splice"].concat(macs$0);});t0$11=getProjector(mac$0("macros"))($targ$4);if(t0$11[0]){macros_mac$0=t0$11[1];}else{___match_error($targ$4,"mac{\"macros\"}! macros_mac{context, info, form and {=> env}, #data{body}}");}mak$0=(function mak(tosave$0){return (function(ph$2$0,info$6,form$4,expr$1){let x$0;let mac$4;let tosave$1;let t0$15;let t1$7;let ph$3$0;if(equal(expr$1,["void"])){return ["nostep",form$4];}else{if(((x$0=ph$2$0),((x$0 instanceof Array)&&(x$0[0]==="pattern")))){mac$4=(function mac(){let m$2;let acc$1;let temp$3;let provides$0;let e$1;let args$1;let body$2;let env$2;let x$1;let $$13704$0;let $$13705$0;let $$13706$0;let t0$13;let t1$5;let t2$3;let t3$2;let t4$2;let t5$0;let ph$5$0;let blah$0;let t0$12;let t1$4;let t2$2;let m$1$0;m$1$0=arguments;t0$12=m$1$0.length;if(((t0$12>=1)&&((blah$0=Array.prototype.slice.call(m$1$0,0,-1)),(t1$4=m$1$0[(t0$12-1)]),(Array.isArray(t1$4)&&((t2$2=t1$4.length),((t2$2===2)&&(t1$4[0]==="data"))))))){ph$5$0=t1$4[1];t0$13=ph$5$0;t1$5=t0$13.length;if((($$13706$0=(t1$5===3))&&(t0$13[0]==="use"))){env$2=t0$13[1];x$1=t0$13[2];return ["use",env$2,mac$4.call(this,["data",x$1])];}else{if(($$13706$0&&((t0$13[0]==="send")&&((t2$3=t0$13[1]),(Array.isArray(t2$3)&&((t3$2=t2$3.length),((t3$2===2)&&((t2$3[0]==="symbol")&&((t2$3[1]==="->")&&((t4$2=t0$13[2]),(Array.isArray(t4$2)&&((t5$0=t4$2.length),((t5$0===3)&&(t4$2[0]==="data")))))))))))))){args$1=t4$2[1];body$2=t4$2[2];e$1=wrap_macro_func$0(info$6,args$1,body$2);acc$1=[];temp$3=null;m$2=null;$5:for(m$2 of tosave$0){let expn$0;let exp$0;let sym$2;let name$2;let t0$14;let t1$6;let t2$4;t0$14=m$2;sym$2=t0$14;if((Array.isArray(t0$14)&&((t1$6=t0$14.length),((t1$6===2)&&((t0$14[0]==="symbol")&&((t2$4=getProjector(camelCase$0)(t0$14[1])),t2$4[0])))))){name$2=t2$4[1];expn$0=("__mdep_"+name$2);exp$0=["symbol",expn$0];temp$3=["multi",["send",["symbol","provide"],["data",["send",["symbol","as"],["data",sym$2,exp$0]]]],["send",["symbol","="],["data",["send",["symbol","deps"],["value",name$2]],["value",expn$0]]]];acc$1.push(temp$3);}else{___match_error(m$2);}}provides$0=acc$1;return ["multi",["send",["symbol","="],["data",["symbol","tmp"],e$1]],["send",["symbol","="],["data",["send",["symbol","and"],["data",["send",["symbol","tmp"],["send",["symbol","."],["data",["void"],["symbol","__deps"]]]],["symbol","deps"]]],["data",["symbol","="]]]]].concat(provides$0).concat([["send",["symbol","="],["data",["send",["symbol","tmp"],["send",["symbol","."],["data",["void"],["symbol","__path"]]]],["symbol","__filename"]]],["symbol","tmp"]]);}else{return ___match_error(ph$5$0,"`^args -> ^body`");}}}else{return ___match_error(m$1$0,"{*blah, #data{match}}");}});return ["project",["macro",mac$4],expr$1,true];}else{ph$3$0=expr$1;t0$15=ph$3$0;t1$7=t0$15.length;if(((t1$7>=1)&&(t0$15[0]==="data"))){tosave$1=Array.prototype.slice.call(t0$15,1);return ["macro",mak$0(tosave$1)];}else{return ___match_error(ph$3$0,"#data{*tosave}");}}}});});$targ$5=mak$0([]);t0$16=getProjector(mac$0("macro"))($targ$5);if(t0$16[0]){macro_mac$0=t0$16[1];}else{___match_error($targ$5,"mac{\"macro\"}! macro_mac");}return exports$0;});(module["exports"]=$targ$0);(void 0); 3 | //# sourceMappingURL=macrodef.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/macros/operators.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let $targ$0;let $0$0;let partial_pattern$0;let make_assigner$0;let overridable$0;$0$0=require("./helpers");partial_pattern$0=getProperty($0$0,"partial_pattern","./helpers");make_assigner$0=getProperty($0$0,"make_assigner","./helpers");overridable$0=getProperty($0$0,"overridable","./helpers");if((typeof(module)==="undefined")){$targ$1=undefined;(global["module"]=$targ$1);(void 0);}$targ$0=(function(mac$0){let m$0;let acc$0;let temp$0;let defns$0;let t0$2;let t0$5;let t1$3;let t0$7;let t1$5;let t0$9;let t1$7;let t0$11;let t1$9;let t0$13;let t1$11;let t0$16;let t0$19;let t1$14;let t0$21;let $targ$2;let is_mac$0;let $targ$3;let minus_mac$0;let $targ$4;let append_mac$0;let $targ$5;let range_mac$0;let $targ$6;let xrange_mac$0;let $targ$7;let floor_mac$0;let $targ$8;let times_mac$0;let $targ$9;let exp_mac$0;let $targ$10;let shift_mac$0;let exports$0;exports$0=({});defns$0=({"===":partial_pattern$0("==="),"!==":partial_pattern$0("!=="),"in":partial_pattern$0("__in__"),"==":partial_pattern$0("equal"),"!=":partial_pattern$0("nequal"),"<=":partial_pattern$0("<="),">=":partial_pattern$0(">="),"<":partial_pattern$0("<"),">":partial_pattern$0(">"),"+=":make_assigner$0("+"),"-=":make_assigner$0("-"),"*=":make_assigner$0("*"),"/=":make_assigner$0("/"),"<<=":make_assigner$0("<<"),">>=":make_assigner$0(">>"),">>>=":make_assigner$0(">>>"),"++=":make_assigner$0("++"),"?=":make_assigner$0("match"),"or=":make_assigner$0("or"),"and=":make_assigner$0("and"),"each=":make_assigner$0("each")});acc$0=[];temp$0=null;m$0=null;$1:for(m$0 of items(defns$0)){let k$0;let v$0;let t0$0;let t1$0;t0$0=m$0;if((Array.isArray(t0$0)&&((t1$0=t0$0.length),(t1$0===2)))){k$0=t0$0[0];v$0=t0$0[1];temp$0=mac$0(k$0)(v$0);acc$0.push(temp$0);}else{___match_error(m$0);}}$targ$2=(function(ph$0$0,temp$1$0,form$0,temp$2$0){let t0$1;let t1$1;let x$1;let x$0;let y$0;t0$1=temp$2$0;if((Array.isArray(t0$1)&&((t1$1=t0$1.length),((t1$1===3)&&(t0$1[0]==="data"))))){x$0=t0$1[1];y$0=t0$1[2];}else{___match_error(temp$2$0);}if(((x$1=ph$0$0),((x$1 instanceof Array)&&(x$1[0]==="pattern")))){return ["replace",x$0,y$0];}else{return ["send",["symbol","==="],["data",x$0,y$0]];}});t0$2=getProjector(mac$0("is"))($targ$2);if(t0$2[0]){is_mac$0=t0$2[1];}else{___match_error($targ$2,"mac{\"is\"}! is_mac{match, _, form, #data{x, y}}");}$targ$3=(function(context$0,temp$3$0,form$1,temp$4$0){let t0$3;let other$0;let n$0;let $$17741$0;let $$17742$0;let t0$4;let t1$2;let t2$0;let t3$0;let t4$0;let t5$0;let t6$0;let expr$0;let ph$1$0;t0$3=temp$4$0;expr$0=t0$3;ph$1$0=t0$3;t0$4=ph$1$0;t1$2=t0$4.length;if(((t1$2===3)&&((t0$4[0]==="data")&&((t2$0=t0$4[1]),(Array.isArray(t2$0)&&((t3$0=t2$0.length),((t3$0===1)&&((t2$0[0]==="void")&&((t4$0=t0$4[2]),(Array.isArray(t4$0)&&((t5$0=t4$0.length),((t5$0===2)&&((t4$0[0]==="value")&&((t6$0=t4$0[1]),(typeof(t6$0)==="number"))))))))))))))){n$0=t6$0;return ["value",(-n$0)];}else{if(((t1$2===1)&&(t0$4[0]==="void"))){return ["variable","-"];}else{other$0=ph$1$0;return ["send",["variable","-"],expr$0];}}});t0$5=getProjector(overridable$0)($targ$3);if((t0$5[0]&&((t1$3=getProjector(mac$0("-"))(t0$5[1])),t1$3[0]))){minus_mac$0=t1$3[1];}else{___match_error($targ$3,"overridable! mac{\"-\"}! minus_mac{context, _, form, match expr}");}$targ$4=(function(context$1,temp$5$0,form$2,ph$2$0){let other$1;let x$4;let y$1;let x$3;let x$2;let $$17817$0;let $$17818$0;let $$17819$0;let $$17820$0;let t0$6;let t1$4;let t2$1;let t3$1;t0$6=ph$2$0;t1$4=t0$6.length;if((($$17819$0=(t1$4===3))&&(($$17820$0=(t0$6[0]==="data"))&&((t2$1=t0$6[1]),(Array.isArray(t2$1)&&((t3$1=t2$1.length),((t3$1===1)&&(t2$1[0]==="void")))))))){x$2=t0$6[2];return ["send",["variable","++"],["data",["void"],x$2]];}else{if(($$17820$0&&((x$3=t0$6[1]),(t2$1=t0$6[2]),(Array.isArray(t2$1)&&((t3$1=t2$1.length),((t3$1===1)&&(t2$1[0]==="void"))))))){return ["send",["variable","++"],["data",x$3,["void"]]];}else{if($$17820$0){x$4=t0$6[1];y$1=t0$6[2];return ["send",["send",x$4,["send",["symbol","."],["data",["void"],["symbol","concat"]]]],["data",y$1]];}else{if(((t1$4===1)&&(t0$6[0]==="void"))){return ["send",["symbol","->"],["data",["data",["symbol","x"],["symbol","y"]],["send",["send",["symbol","x"],["send",["symbol","."],["data",["void"],["symbol","concat"]]]],["data",["symbol","y"]]]]];}else{other$1=ph$2$0;return ["send",["symbol","___build_array"],["data",other$1]];}}}}});t0$7=getProjector(overridable$0)($targ$4);if((t0$7[0]&&((t1$5=getProjector(mac$0("++"))(t0$7[1])),t1$5[0]))){append_mac$0=t1$5[1];}else{___match_error($targ$4,"overridable! mac{\"++\"}! append_mac{context, _, form, match}");}$targ$5=(function(context$2,temp$6$0,form$3,ph$3$0){let x$7;let y$2;let x$6;let x$5;let $$17889$0;let $$17890$0;let $$17891$0;let $$17892$0;let t0$8;let t1$6;let t2$2;let t3$2;t0$8=ph$3$0;t1$6=t0$8.length;if((($$17891$0=(t1$6===3))&&(($$17892$0=(t0$8[0]==="data"))&&((t2$2=t0$8[1]),(Array.isArray(t2$2)&&((t3$2=t2$2.length),((t3$2===1)&&(t2$2[0]==="void")))))))){x$5=t0$8[2];return ["send",["symbol","range"],["data",["value",1],x$5]];}else{if(($$17892$0&&((x$6=t0$8[1]),(t2$2=t0$8[2]),(Array.isArray(t2$2)&&((t3$2=t2$2.length),((t3$2===1)&&(t2$2[0]==="void"))))))){return ["send",["symbol","range"],["data",x$6]];}else{if($$17892$0){x$7=t0$8[1];y$2=t0$8[2];return ["send",["symbol","range"],["data",x$7,y$2]];}else{if(((t1$6===1)&&(t0$8[0]==="void"))){return ["symbol","range"];}else{return ___match_error(ph$3$0,"#void{}");}}}}});t0$9=getProjector(overridable$0)($targ$5);if((t0$9[0]&&((t1$7=getProjector(mac$0(".."))(t0$9[1])),t1$7[0]))){range_mac$0=t1$7[1];}else{___match_error($targ$5,"overridable! mac{\"..\"}! range_mac{context, _, form, match}");}$targ$6=(function(context$3,temp$7$0,form$4,ph$4$0){let x$10;let y$3;let x$9;let x$8;let $$17960$0;let $$17961$0;let $$17962$0;let $$17963$0;let t0$10;let t1$8;let t2$3;let t3$3;t0$10=ph$4$0;t1$8=t0$10.length;if((($$17962$0=(t1$8===3))&&(($$17963$0=(t0$10[0]==="data"))&&((t2$3=t0$10[1]),(Array.isArray(t2$3)&&((t3$3=t2$3.length),((t3$3===1)&&(t2$3[0]==="void")))))))){x$8=t0$10[2];return ["send",["symbol","range"],["data",["value",0],["send",["symbol","-"],["data",x$8,["value",1]]]]];}else{if(($$17963$0&&((x$9=t0$10[1]),(t2$3=t0$10[2]),(Array.isArray(t2$3)&&((t3$3=t2$3.length),((t3$3===1)&&(t2$3[0]==="void"))))))){return ["send",["symbol","range"],["data",x$9]];}else{if($$17963$0){x$10=t0$10[1];y$3=t0$10[2];return ["send",["symbol","range"],["data",x$10,["send",["symbol","-"],["data",y$3,["value",1]]]]];}else{return ___match_error(ph$4$0,"#data{x, y}");}}}});t0$11=getProjector(overridable$0)($targ$6);if((t0$11[0]&&((t1$9=getProjector(mac$0("..."))(t0$11[1])),t1$9[0]))){xrange_mac$0=t1$9[1];}else{___match_error($targ$6,"overridable! mac{\"...\"}! xrange_mac{context, _, form, match}");}$targ$7=(function(context$4,temp$8$0,form$5,ph$5$0){let a$0;let b$0;let $$18027$0;let $$18028$0;let t0$12;let t1$10;t0$12=ph$5$0;t1$10=t0$12.length;if(((t1$10===1)&&(t0$12[0]==="void"))){return ["send",["symbol","->"],["data",["data",["symbol","a"],["symbol","b"]],["send",["send",["symbol","Math"],["send",["symbol","."],["data",["void"],["symbol","floor"]]]],["data",["send",["symbol","/"],["data",["symbol","a"],["symbol","b"]]]]]]];}else{if(((t1$10===3)&&(t0$12[0]==="data"))){a$0=t0$12[1];b$0=t0$12[2];return ["send",["send",["symbol","Math"],["send",["symbol","."],["data",["void"],["symbol","floor"]]]],["data",["send",["symbol","/"],["data",a$0,b$0]]]];}else{return ___match_error(ph$5$0,"#data{a, b}");}}});t0$13=getProjector(overridable$0)($targ$7);if((t0$13[0]&&((t1$11=getProjector(mac$0("//"))(t0$13[1])),t1$11[0]))){floor_mac$0=t1$11[1];}else{___match_error($targ$7,"overridable! mac{\"//\"}! floor_mac{context, _, form, match}");}$targ$8=(function(context$5,temp$9$0,form$6,expr$1){let x$11;let x$12;let t0$15;let other$2;let val$0;let $$18073$0;let $$18074$0;let $$18075$0;let t0$14;let t1$12;let t2$4;let bridge$$18070$0;let t3$4;let t4$1;let m$1$0;m$1$0=[context$5,expr$1];if((($$18073$0=Array.isArray(m$1$0))&&((t0$14=m$1$0.length),(($$18075$0=(t0$14===2))&&(((x$11=m$1$0[0]),((x$11 instanceof Array)&&(x$11[0]==="pattern")))&&((t1$12=m$1$0[1]),(Array.isArray(t1$12)&&((t2$4=t1$12.length),((t2$4===1)&&(t1$12[0]==="void")))))))))){return ["dynsplice",["ignore"]];}else{if(($$18075$0&&((bridge$$18070$0=m$1$0[0]),((((x$12=bridge$$18070$0),((x$12 instanceof Array)&&(x$12[0]==="pattern")))||(Array.isArray(bridge$$18070$0)&&((t0$15=bridge$$18070$0.length),((t0$15===2)&&((bridge$$18070$0[0]==="expr")&&(bridge$$18070$0[1]==="data"))))))&&((t1$12=m$1$0[1]),(Array.isArray(t1$12)&&((t2$4=t1$12.length),((t2$4===3)&&((t1$12[0]==="data")&&((t3$4=t1$12[1]),(Array.isArray(t3$4)&&((t4$1=t3$4.length),((t4$1===1)&&(t3$4[0]==="void")))))))))))))){val$0=t1$12[2];return ["dynsplice",val$0];}else{if(($$18075$0&&(m$1$0[0],(t1$12=m$1$0[1]),(Array.isArray(t1$12)&&((t2$4=t1$12.length),((t2$4===1)&&(t1$12[0]==="void"))))))){return ["variable","*"];}else{other$2=m$1$0;return ["send",["variable","*"],expr$1];}}}});t0$16=getProjector(mac$0("*"))($targ$8);if(t0$16[0]){times_mac$0=t0$16[1];}else{___match_error($targ$8,"mac{\"*\"}! times_mac{context, _, form, expr}");}$targ$9=(function(context$6,temp$10$0,form$7,expr$2){let x$13;let x$14;let t0$18;let a$1;let b$1;let val$1;let $$18180$0;let $$18181$0;let $$18182$0;let $$18183$0;let $$18184$0;let $$18185$0;let $$18186$0;let t0$17;let t1$13;let t2$5;let bridge$$18177$0;let t3$5;let t4$2;let m$2$0;m$2$0=[context$6,expr$2];if((($$18180$0=Array.isArray(m$2$0))&&((t0$17=m$2$0.length),(($$18182$0=(t0$17===2))&&(((x$13=m$2$0[0]),((x$13 instanceof Array)&&(x$13[0]==="pattern")))&&((t1$13=m$2$0[1]),(Array.isArray(t1$13)&&((t2$5=t1$13.length),((t2$5===1)&&(t1$13[0]==="void")))))))))){return ["objsplice",["ignore"]];}else{if(($$18182$0&&((bridge$$18177$0=m$2$0[0]),((((x$14=bridge$$18177$0),((x$14 instanceof Array)&&(x$14[0]==="pattern")))||(Array.isArray(bridge$$18177$0)&&((t0$18=bridge$$18177$0.length),((t0$18===2)&&((bridge$$18177$0[0]==="expr")&&(bridge$$18177$0[1]==="data"))))))&&((t1$13=m$2$0[1]),(Array.isArray(t1$13)&&((t2$5=t1$13.length),((t2$5===3)&&((t1$13[0]==="data")&&((t3$5=t1$13[1]),(Array.isArray(t3$5)&&((t4$2=t3$5.length),((t4$2===1)&&(t3$5[0]==="void")))))))))))))){val$1=t1$13[2];return ["objsplice",val$1];}else{if(($$18182$0&&(m$2$0[0],(t1$13=m$2$0[1]),(($$18185$0=Array.isArray(t1$13))&&((t2$5=t1$13.length),((t2$5===1)&&(t1$13[0]==="void"))))))){return ["send",["symbol","Math"],["send",["symbol","."],["data",["void"],["symbol","pow"]]]];}else{if(($$18185$0&&((t2$5===3)&&(t1$13[0]==="data")))){a$1=t1$13[1];b$1=t1$13[2];return ["send",["send",["symbol","Math"],["send",["symbol","."],["data",["void"],["symbol","pow"]]]],["data",a$1,b$1]];}else{return ___match_error(m$2$0,"{_, #data{a, b}}");}}}}});t0$19=getProjector(overridable$0)($targ$9);if((t0$19[0]&&((t1$14=getProjector(mac$0("**"))(t0$19[1])),t1$14[0]))){exp_mac$0=t1$14[1];}else{___match_error($targ$9,"overridable! mac{\"**\"}! exp_mac{context, _, form, expr}");}$targ$10=(function(ph$6$0,temp$11$0,form$8,expr$3){let x$15;let t0$20;let t1$15;let $targ$11;let variable$0;let result$0;if(((x$15=ph$6$0),((x$15 instanceof Array)&&(x$15[0]==="pattern")))){$targ$11=expr$3;t0$20=$targ$11;if((Array.isArray(t0$20)&&((t1$15=t0$20.length),((t1$15===3)&&(t0$20[0]==="data"))))){variable$0=t0$20[1];result$0=t0$20[2];}else{___match_error($targ$11,"#data{variable, result}");}[variable$0,result$0];return ["project",["send",["symbol","->"],["data",["data",variable$0],["data",["symbol","true"],result$0]]],variable$0];}else{return ["send",["variable",">>"],expr$3];}});t0$21=getProjector(mac$0(">>"))($targ$10);if(t0$21[0]){shift_mac$0=t0$21[1];}else{___match_error($targ$10,"mac{\">>\"}! shift_mac{match, _, form, expr}");}return exports$0;});(module["exports"]=$targ$0);(void 0); 3 | //# sourceMappingURL=operators.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/macros/quote.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let $targ$0;let $0$0;let unescape$0;let $1$0;let Source$0;let $2$0;let qq$0;let overridable$0;let opg$0;$0$0=require("../lex");unescape$0=getProperty($0$0,"unescape","../lex");$1$0=require("../location");Source$0=getProperty($1$0,"Source","../location");$2$0=require("./helpers");qq$0=getProperty($2$0,"qq","./helpers");overridable$0=getProperty($2$0,"overridable","./helpers");opg$0=require("opg");if((typeof(module)==="undefined")){$targ$1=undefined;(global["module"]=$targ$1);(void 0);}$targ$0=(function(mac$0){let t0$3;let t0$6;let t0$17;let t1$10;let t0$21;let $targ$2;let unquote_mac$0;let $targ$3;let quote_mac$0;let tok$0;let gr$0;let prio$0;let finalize$0;let parser$0;let parse$0;let $targ$4;let wq_mac$0;let $targ$5;let interpolate_mac$0;let exports$0;exports$0=({});$targ$2=(function(temp$0$0,info$0,form$0,expr$0){let t0$0;let x$0;let t0$2;let t1$1;let t2$0;let t3$0;let $targ$6;let x$1;let t0$1;let t1$0;let context$0;let ph$0$0;t0$0=temp$0$0;context$0=t0$0;ph$0$0=t0$0;t0$1=ph$0$0;t1$0=t0$1.length;if(((t1$0===2)&&((t0$1[0]==="expr")&&(t0$1[1]==="head")))){return ["nostep"];}else{if(((x$0=ph$0$0),((x$0 instanceof Array)&&(x$0[0]==="pattern")))){$targ$6=expr$0;t0$2=$targ$6;if((Array.isArray(t0$2)&&((t1$1=t0$2.length),((t1$1===3)&&((t0$2[0]==="data")&&((t2$0=t0$2[1]),(Array.isArray(t2$0)&&((t3$0=t2$0.length),((t3$0===1)&&(t2$0[0]==="void")))))))))){x$1=t0$2[2];}else{___match_error($targ$6,"#data{#void{}, x}");}return ["calc",x$1];}else{throw send(send(ErrorFactory(["syntax","unquote"]),"create", true),__amp____colon__([(("Cannot unquote in context "+context$0)+".")],({"expr":expr$0,"::objinsert":1})));}}});t0$3=getProjector(mac$0("^"))($targ$2);if(t0$3[0]){unquote_mac$0=t0$3[1];}else{___match_error($targ$2,"mac{\"^\"}! unquote_mac{match context, info, form, expr}");}$targ$3=(function(temp$1$0,info$1,form$1,temp$2$0){let t0$4;let t0$5;let t1$2;let parsed$0;let context$1;let ph$1$0;let expr$1;let s$0;t0$4=temp$1$0;context$1=t0$4;ph$1$0=t0$4;t0$5=temp$2$0;expr$1=t0$5;if((Array.isArray(t0$5)&&((t1$2=t0$5.length),((t1$2===2)&&(t0$5[0]==="value"))))){s$0=t0$5[1];}else{___match_error(temp$2$0);}parsed$0=info$1.go(Source$0(s$0,""),"source","parse");return info$1.mark(qq$0(parsed$0));});t0$6=getProjector(mac$0("`"))($targ$3);if(t0$6[0]){quote_mac$0=t0$6[1];}else{___match_error($targ$3,"mac{\"`\"}! quote_mac{match context, info, form, expr and #value{s}}");}tok$0=opg$0.tokenize.Tokenizer(({"regexps":({"open":"\\{","close":"\\}","other":"(?:\\\\.|[^\\{\\}])+"}),"post":[(function(temp$3$0){let t0$7;let t0$8;let tok$1;let ph$2$0;t0$7=temp$3$0;tok$1=t0$7;ph$2$0=t0$7;t0$8=ph$2$0;if((___hasprop(t0$8,"type")&&(t0$8.type==="open"))){return [({"token":"","type":"other","location":tok$1.location.at_start()}),tok$1];}else{return tok$1;}})]}));gr$0=(new opg$0.parse.TokenGroups(({"open":["open"],"close":["close"],"other":["str","other"]})));prio$0=(new opg$0.parse.PriorityOrder(gr$0,({"open":({"left":1002,"right":0}),"close":({"left":0,"right":1003}),"other":({"left":1000,"right":1000})})));finalize$0=(function finalize(temp$4$0){let t0$9;let t0$11;let t1$4;let t2$2;let tag$0;let arg$0;let text$0;let bridge$$18544$0;let m$0;let rval$0;let text$1;let args$0;let token$0;let open$0;let ph$4$0;let _arg$0;let close$0;let $$18547$0;let $$18548$0;let t0$10;let t1$3;let t2$1;let t3$1;let t4$0;let zazz$0;let ph$3$0;t0$9=temp$4$0;zazz$0=t0$9;ph$3$0=t0$9;t0$10=ph$3$0;t1$3=t0$10.length;if(((t1$3===5)&&((t0$10[0]===null)&&((t2$1=t0$10[1]),(___hasprop(t2$1,"type")&&((t2$1.type==="open")&&(___hasprop(t2$1,"token")&&((t3$1=t2$1.token),(open$0=t3$1),(ph$4$0=t3$1),(_arg$0=t0$10[2]),(t4$0=t0$10[3]),(___hasprop(t4$0,"type")&&((t4$0.type==="close")&&(___hasprop(t4$0,"token")&&((close$0=t4$0.token),(t0$10[4]===null))))))))))))){arg$0=(_arg$0||__amp__(["join",""],({"text":""})));text$0=((open$0+arg$0.text)+close$0);bridge$$18544$0=ph$4$0;if((((t0$11=getProjector(RegExp("\\$([^\\{]*){",""))(bridge$$18544$0)),(t0$11[0]&&((t1$4=t0$11[1]),(t2$2=t1$4.length),((t2$2===2)&&(t1$4[0],(tag$0=t1$4[1]),true)))))||((tag$0=""),true))){return __amp____colon__(["bracket",tag$0,arg$0.text],({"text":text$0}));}else{return ___match_error(ph$4$0,"R\"\\$([^\\{]*){\"! {_, tag} or tag is \"\"");}}else{if(((t1$3===3)&&((t0$10[0]===null)&&((t2$1=t0$10[1]),(___hasprop(t2$1,"token")&&((token$0=t2$1.token),(t0$10[2]===null))))))){return __amp____colon__(["join",token$0],({"text":token$0}));}else{args$0=ph$3$0;rval$0=["join"];text$1="";m$0=null;$3:for(m$0 of enumerate(args$0)){let x$2;let sub$0;let token$1;let $$18649$0;let t0$13;let t1$6;let i$0;let arg$1;let ph$5$0;let t0$12;let t1$5;let t2$3;t0$12=m$0;if((Array.isArray(t0$12)&&((t1$5=t0$12.length),(t1$5===2)))){i$0=t0$12[0];t2$3=t0$12[1];arg$1=t2$3;ph$5$0=t2$3;t0$13=ph$5$0;if((___hasprop(t0$13,"token")&&((token$1=t0$13.token),equal((i$0%2),1)))){rval$0.push(token$1);text$1=(text$1+token$1);}else{if((Array.isArray(t0$13)&&((t1$6=t0$13.length),((t1$6>=1)&&(t0$13[0]==="join"))))){sub$0=Array.prototype.slice.call(t0$13,1);text$1=(text$1+arg$1.text);rval$0=rval$0.concat(sub$0);}else{if(((x$2=ph$5$0),((x$2 instanceof Array)&&(x$2[0]==="bracket")))){text$1=(text$1+arg$1.text);rval$0.push(arg$1);}else{if((ph$5$0===null)){undefined;}else{___match_error(ph$5$0);}}}}}else{___match_error(m$0);}}return __amp____colon__(rval$0,({"text":text$1}));}}});parser$0=(new opg$0.parse.Parser(tok$0,prio$0.getOrder(),finalize$0));parse$0=(function parse(text$2){return parser$0.parse(text$2);});$targ$4=(function(context$2,info$2,form$2,temp$5$0){let t0$14;let t1$7;let f$0;let f$1;let v$0;let $$18731$0;let $$18732$0;let $$18733$0;let t0$16;let t1$9;let t2$5;let t3$3;let elements$0;let ph$6$0;let t0$15;let t1$8;let t2$4;let t3$2;let t4$1;let t5$0;let t6$0;let t7$0;let t8$0;let t9$0;let t10$0;let t11$0;let t12$0;let m$1$0;let x$3;t0$14=temp$5$0;if((Array.isArray(t0$14)&&((t1$7=t0$14.length),((t1$7===2)&&(t0$14[0]==="data"))))){x$3=t0$14[1];}else{___match_error(temp$5$0);}m$1$0=x$3;if((Array.isArray(m$1$0)&&((t0$15=m$1$0.length),((t0$15===3)&&((m$1$0[0]==="send")&&((t1$8=m$1$0[1]),(Array.isArray(t1$8)&&((t2$4=t1$8.length),((t2$4===2)&&((t1$8[0]==="symbol")&&((t1$8[1]==="ENode")&&((t3$2=m$1$0[2]),(Array.isArray(t3$2)&&((t4$1=t3$2.length),((t4$1===4)&&((t3$2[0]==="data")&&((t5$0=t3$2[1]),(Array.isArray(t5$0)&&((t6$0=t5$0.length),((t6$0===1)&&((t5$0[0]==="data")&&((t7$0=t3$2[2]),(Array.isArray(t7$0)&&((t8$0=t7$0.length),((t8$0===2)&&((t7$0[0]==="data")&&((t9$0=t7$0[1]),(Array.isArray(t9$0)&&((t10$0=t9$0.length),((t10$0===2)&&((t9$0[0]==="symbol")&&((t9$0[1]==="=")&&((t11$0=t3$2[3]),(Array.isArray(t11$0)&&((t12$0=t11$0.length),((t12$0>=1)&&(t11$0[0]==="data"))))))))))))))))))))))))))))))))))))){elements$0=Array.prototype.slice.call(t11$0,1);ph$6$0=elements$0;t0$16=ph$6$0;if((($$18732$0=Array.isArray(t0$16))&&((t1$9=t0$16.length),((t1$9===1)&&((t2$5=t0$16[0]),(v$0=t2$5),(Array.isArray(t2$5)&&((t3$3=t2$5.length),((t3$3===2)&&((t2$5[0]==="value")&&(typeof(t2$5[1])==="string")))))))))){return v$0;}else{if(($$18732$0&&((t1$9>=1)&&((t2$5=t0$16[0]),(Array.isArray(t2$5)&&((t3$3=t2$5.length),((t3$3===2)&&((t2$5[0]==="value")&&(typeof(t2$5[1])==="string"))))))))){Array.prototype.slice.call(t0$16,1);f$0=(function f(x$4,y$0){return ["send",["symbol","+"],["data",x$4,y$0]];});return elements$0.reduce(f$0);}else{f$1=(function f(x$5,y$1){return ["send",["symbol","+"],["data",x$5,y$1]];});return elements$0.reduce(f$1,["value",""]);}}}else{return ["send",["send",x$3,["send",["symbol","."],["data",["void"],["symbol","to-string"]]]],["data"]];}});t0$17=getProjector(overridable$0)($targ$4);if((t0$17[0]&&((t1$10=getProjector(mac$0("wrap-quote"))(t0$17[1])),t1$10[0]))){wq_mac$0=t1$10[1];}else{___match_error($targ$4,"overridable! mac{\"wrap-quote\"}! wq_mac{context, info, form, `{^x}`}");}$targ$5=(function(context$3,info$3,form$3,temp$6$0){let t0$18;let t1$11;let t0$19;let bridge$$18912$0;let m$2;let $targ$7;let contents$0;let parts$0;let current$0;let push$0;let wq$0;let s$1;t0$18=temp$6$0;if((Array.isArray(t0$18)&&((t1$11=t0$18.length),((t1$11===2)&&(t0$18[0]==="value"))))){s$1=t0$18[1];}else{___match_error(temp$6$0);}$targ$7=parse$0(s$1);bridge$$18912$0=$targ$7;if(((Array.isArray(bridge$$18912$0)&&((t0$19=bridge$$18912$0.length),((t0$19>=1)&&((bridge$$18912$0[0]==="join")&&((contents$0=Array.prototype.slice.call(bridge$$18912$0,1)),true)))))||((contents$0=[]),true))){}else{___match_error($targ$7,"#join{*contents} or contents is {}");}parts$0=[];current$0="";push$0=(function push(){if(nequal(current$0,"")){parts$0.push(["value",current$0]);current$0="";return current$0;}});m$2=null;$4:for(m$2 of contents$0){let p$0;let ph$7$0;let expr$2;let s$2;let $$18921$0;let t0$20;let t1$12;t0$20=m$2;if((typeof(t0$20)==="string")){s$2=t0$20;current$0=(current$0+unescape$0(s$2));}else{if((Array.isArray(t0$20)&&((t1$12=t0$20.length),((t1$12===3)&&(t0$20[0]==="bracket"))))){ph$7$0=t0$20[1];expr$2=t0$20[2];push$0();p$0=form$3.env.mark(["parse",expr$2]);if((ph$7$0==="")){parts$0.push(p$0);}else{___match_error(ph$7$0);}}else{___match_error(m$2);}}}push$0();wq$0=form$3.env.mark(["symbol","wrap-quote"]);return ["send",wq$0,["data",["send",["symbol","ENode"],["data",["data"],["data",["symbol","="]],["data"].concat(parts$0)]]]];});t0$21=getProjector(mac$0("'"))($targ$5);if(t0$21[0]){interpolate_mac$0=t0$21[1];}else{___match_error($targ$5,"mac{\"'\"}! interpolate_mac{context, info, form, #value{s}}");}return exports$0;});(module["exports"]=$targ$0);(void 0); 3 | //# sourceMappingURL=quote.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/macros/regexp.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$1;let $targ$0;let $0$0;let Source$0;let $1$0;let accum_flags$0;$0$0=require("../location");Source$0=getProperty($0$0,"Source","../location");$1$0=require("./helpers");accum_flags$0=getProperty($1$0,"accum_flags","./helpers");if((typeof(module)==="undefined")){$targ$1=undefined;(global["module"]=$targ$1);(void 0);}$targ$0=(function(mac$0){let $targ$10;let accum$0;let $targ$11;let accum$1;let t0$9;let t1$9;let RegexBuilder$0;let build_regexp$0;let accum_flagsf$0;let $targ$2;let regexp_mac$0;let exports$0;exports$0=({});RegexBuilder$0=(function RegexBuilder(){let __at___$0;if((!getChecker(RegexBuilder$0)(this))){__at___$0=Object.create(RegexBuilder$0.prototype);}else{__at___$0=this;}return __at___$0;});(RegexBuilder$0.prototype["wrap"]=(function wrap(x$0){let __at___$1;let self$0;__at___$1=this;self$0=this;return (("(?:"+x$0)+")");}));(RegexBuilder$0.prototype["quote"]=(function quote(x$1){let __at___$2;let self$1;__at___$2=this;self$1=this;return x$1.replace(RegExp("([.?*+\\^$\\[\\]\\(\\)\\{\\}|\\\\])","g"),"\\$1");}));(RegexBuilder$0.prototype["quote_charset"]=(function quote_charset(x$2){let __at___$3;let self$2;__at___$3=this;self$2=this;return x$2.replace(RegExp("([\\[\\]\\(\\)\\{\\}\\^])","g"),"\\$1");}));(RegexBuilder$0.prototype["build"]=(function build(expr$0){let t0$1;let t1$1;let $targ$3;let t0$2;let t1$2;let $targ$4;let t0$3;let t1$3;let $targ$5;let t0$4;let t1$4;let t0$5;let t1$5;let x$4;let $targ$6;let $targ$7;let v$0;let t0$6;let t1$6;let t0$7;let t1$7;let t2$1;let t3$1;let t4$1;let t5$0;let t6$0;let t7$0;let t8$0;let t9$0;let x$5;let $targ$8;let $targ$9;let v$1;let m$1;let acc$0;let temp$0;let m$2;let acc$1;let temp$1;let other$0;let args$1;let args$0;let ph$1$0;let a$0;let b$0;let s$0;let x$3;let ph$0$0;let $$19142$0;let $$19143$0;let $$19144$0;let $$19145$0;let $$19146$0;let $$19147$0;let $$19148$0;let $$19149$0;let $$19150$0;let t0$0;let t1$0;let t2$0;let t3$0;let t4$0;let m$0$0;let __at___$4;let self$3;__at___$4=this;self$3=this;m$0$0=expr$0;if((($$19142$0=Array.isArray(m$0$0))&&((t0$0=m$0$0.length),(($$19144$0=(t0$0===2))&&(m$0$0[0]==="symbol"))))){ph$0$0=m$0$0[1];if((ph$0$0==="any")){return ".";}else{if((ph$0$0==="start")){return "^";}else{if((ph$0$0==="end")){return "$";}else{if((ph$0$0==="alpha")){return "\\a";}else{if((ph$0$0==="digit")){return "\\d";}else{if((ph$0$0==="word")){return "\\w";}else{if((ph$0$0==="space")){return "\\s";}else{if((ph$0$0==="boundary")){return "\\b";}else{if((ph$0$0==="a")){return "\\a";}else{if((ph$0$0==="d")){return "\\d";}else{if((ph$0$0==="w")){return "\\w";}else{if((ph$0$0==="s")){return "\\s";}else{if((ph$0$0==="b")){return "\\b";}else{return ___match_error(ph$0$0,".b");}}}}}}}}}}}}}}else{if(($$19144$0&&(m$0$0[0]==="value"))){x$3=m$0$0[1];return __at___$4.quote(x$3);}else{if(($$19142$0&&(($$19144$0=(t0$0===3))&&(($$19145$0=(m$0$0[0]==="send"))&&((t1$0=m$0$0[1]),(($$19147$0=Array.isArray(t1$0))&&((t2$0=t1$0.length),(($$19149$0=(t2$0===2))&&(($$19150$0=(t1$0[0]==="symbol"))&&((t1$0[1]==="raw")&&((t3$0=m$0$0[2]),(Array.isArray(t3$0)&&((t4$0=t3$0.length),((t4$0===2)&&(t3$0[0]==="value"))))))))))))))){s$0=t3$0[1];return s$0;}else{if(($$19150$0&&((ph$1$0=t1$0[1]),(t3$0=m$0$0[2]),(Array.isArray(t3$0)&&((t4$0=t3$0.length),((t4$0===3)&&(t3$0[0]==="data"))))))){a$0=t3$0[1];b$0=t3$0[2];if((ph$1$0==="||")){return __at___$4.wrap(((__at___$4.build(a$0)+"|")+__at___$4.build(b$0)));}else{if((ph$1$0==="or")){return __at___$4.wrap(((__at___$4.build(a$0)+"|")+__at___$4.build(b$0)));}else{if((ph$1$0==="*")){$targ$3=a$0;t0$1=$targ$3;if((Array.isArray(t0$1)&&((t1$1=t0$1.length),((t1$1===1)&&(t0$1[0]==="void"))))){}else{___match_error($targ$3,"#void{}");}return __at___$4.wrap((__at___$4.build(b$0)+"*"));}else{if((ph$1$0==="+")){$targ$4=a$0;t0$2=$targ$4;if((Array.isArray(t0$2)&&((t1$2=t0$2.length),((t1$2===1)&&(t0$2[0]==="void"))))){}else{___match_error($targ$4,"#void{}");}return __at___$4.wrap((__at___$4.build(b$0)+"+"));}else{if((ph$1$0==="?")){$targ$5=a$0;t0$3=$targ$5;if((Array.isArray(t0$3)&&((t1$3=t0$3.length),((t1$3===1)&&(t0$3[0]==="void"))))){}else{___match_error($targ$5,"#void{}");}return __at___$4.wrap((__at___$4.build(b$0)+"?"));}else{if((ph$1$0==="in")){$targ$6=a$0;t0$4=$targ$6;if((Array.isArray(t0$4)&&((t1$4=t0$4.length),((t1$4===1)&&(t0$4[0]==="void"))))){}else{___match_error($targ$6,"#void{}");}$targ$7=b$0;t0$5=$targ$7;if((Array.isArray(t0$5)&&((t1$5=t0$5.length),((t1$5===2)&&(t0$5[0]==="value"))))){v$0=t0$5[1];}else{___match_error($targ$7,"#value{v}");}x$4=__at___$4.quote_charset(v$0);return (("["+x$4)+"]");}else{if((ph$1$0==="not")){$targ$8=a$0;t0$6=$targ$8;if((Array.isArray(t0$6)&&((t1$6=t0$6.length),((t1$6===1)&&(t0$6[0]==="void"))))){}else{___match_error($targ$8,"#void{}");}$targ$9=b$0;t0$7=$targ$9;if((Array.isArray(t0$7)&&((t1$7=t0$7.length),((t1$7===3)&&((t0$7[0]==="send")&&((t2$1=t0$7[1]),(Array.isArray(t2$1)&&((t3$1=t2$1.length),((t3$1===2)&&((t2$1[0]==="symbol")&&((t2$1[1]==="in")&&((t4$1=t0$7[2]),(Array.isArray(t4$1)&&((t5$0=t4$1.length),((t5$0===3)&&((t4$1[0]==="data")&&((t6$0=t4$1[1]),(Array.isArray(t6$0)&&((t7$0=t6$0.length),((t7$0===1)&&((t6$0[0]==="void")&&((t8$0=t4$1[2]),(Array.isArray(t8$0)&&((t9$0=t8$0.length),((t9$0===2)&&(t8$0[0]==="value")))))))))))))))))))))))))){v$1=t8$0[1];}else{___match_error($targ$9,"#send{#symbol{\"in\"}, #data{#void{}, #value{v}}}");}x$5=__at___$4.quote_charset(v$1);return (("[^"+x$5)+"]");}else{return ___match_error(ph$1$0,"\"not\"");}}}}}}}}else{if(($$19142$0&&(($$19144$0=(t0$0>=1))&&(m$0$0[0]==="data")))){args$0=Array.prototype.slice.call(m$0$0,1);return (("("+((acc$0=[]),(temp$0=null),(m$1=null),(function(){$6:for(m$1 of args$0){let arg$0;arg$0=m$1;temp$0=__at___$4.build(arg$0);acc$0.push(temp$0);}})(),acc$0).join(""))+")");}else{if(($$19144$0&&(m$0$0[0]==="multi"))){args$1=Array.prototype.slice.call(m$0$0,1);return (("(?:"+((acc$1=[]),(temp$1=null),(m$2=null),(function(){$11:for(m$2 of args$1){let arg$1;arg$1=m$2;temp$1=__at___$4.build(arg$1);acc$1.push(temp$1);}})(),acc$1).join(""))+")");}else{other$0=m$0$0;return ErrorFactory(["syntax","regexp"]).create("Illegal regular expression",({"expr":expr$0}));}}}}}}}));__amp____colon__(RegexBuilder$0,__amp____colon__((($targ$10="RegexBuilder"),(accum$0=({})),(accum$0["::name"]=$targ$10),accum$0),(($targ$11=true),(accum$1=({})),(accum$1["::egclass"]=$targ$11),accum$1)));build_regexp$0=(function build_regexp(x$6){return RegexBuilder$0().build(x$6);});accum_flagsf$0=(function accum_flagsf(f$0){return accum_flags$0(f$0,false);});$targ$2=(function(ph$2$0,info$0,form$0,arg$2,flags$0){let x$7;let x$8;let text$2;let text$1;let m$4$0;let text$0;let s$1;let arg$3;let v$2;let $$19549$0;let $$19550$0;let $$19551$0;let $$19552$0;let $$19553$0;let $$19554$0;let $$19555$0;let $$19556$0;let $$19557$0;let t0$8;let t1$8;let t2$2;let t3$2;let t4$2;let t5$1;let t6$1;let m$3$0;let bridge$$19521$0;bridge$$19521$0=ph$2$0;if((((x$7=bridge$$19521$0),((x$7 instanceof Array)&&(x$7[0]==="check")))||((x$8=bridge$$19521$0),((x$8 instanceof Array)&&(x$8[0]==="project"))))){return ["nostep",form$0];}else{m$3$0=arg$2;if((($$19549$0=Array.isArray(m$3$0))&&((t0$8=m$3$0.length),((t0$8===2)&&((m$3$0[0]==="value")&&((t1$8=m$3$0[1]),(typeof(t1$8)==="string"))))))){v$2=t1$8;m$4$0=info$0.gettext(arg$2);if(getChecker(RegExp("^\\\".*\\\"$",""))(m$4$0)){text$1=m$4$0;text$0=text$1.substring(1,(text$1.length-1));}else{text$2=m$4$0;text$0=text$2;}return ["send",["symbol","RegExp"],["data",["value",text$0],["value",flags$0.join("")]]];}else{if(($$19549$0&&(($$19551$0=(t0$8===3))&&(($$19552$0=(m$3$0[0]==="send"))&&((t1$8=m$3$0[1]),(($$19554$0=Array.isArray(t1$8))&&((t2$2=t1$8.length),(($$19556$0=(t2$2===2))&&(($$19557$0=(t1$8[0]==="symbol"))&&((t1$8[1]==="'")&&((t3$2=m$3$0[2]),(Array.isArray(t3$2)&&((t4$2=t3$2.length),((t4$2===3)&&((t3$2[0]==="data")&&((t5$1=t3$2[1]),(Array.isArray(t5$1)&&((t6$1=t5$1.length),((t6$1===1)&&(t5$1[0]==="void")))))))))))))))))))){arg$3=t3$2[2];return ["send",["symbol","RegExp"],["data",["value",build_regexp$0(arg$3)],["value",flags$0.join("")]]];}else{if(($$19557$0&&((t1$8[1]==="`")&&((t3$2=m$3$0[2]),(Array.isArray(t3$2)&&((t4$2=t3$2.length),((t4$2===2)&&(t3$2[0]==="value")))))))){s$1=t3$2[1];arg$2=info$0.go(Source$0(s$1,""),"source","parse");return ["send",["symbol","RegExp"],["data",["value",build_regexp$0(arg$2)],["value",flags$0.join("")]]];}else{return ___match_error(m$3$0,"#send{#symbol{\"`\"}, #value{s}}");}}}}});t0$9=getProjector(accum_flagsf$0)($targ$2);if((t0$9[0]&&((t1$9=getProjector(mac$0("R"))(t0$9[1])),t1$9[0]))){regexp_mac$0=t1$9[1];}else{___match_error($targ$2,"accum_flagsf! mac{\"R\"}! regexp_mac{match, info, form, var arg, flags}");}return exports$0;});(module["exports"]=$targ$0);(void 0); 3 | //# sourceMappingURL=regexp.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/opt.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$12;let $targ$13;let $0$0;let __lt____lt____colon__$0;let s$0;let varstats$0;let replaceVars$0;let eliminate_spurious_variables$0;let hoist$0;let hoistable$0;let not_hoistable$0;let hoist_helper$0;$0$0=require("./location");__lt____lt____colon__$0=getProperty($0$0,"<<:","./location");s$0=(function s(stats$0,v$0){let $targ$0;if((!Object.hasOwnProperty.call(stats$0,v$0))){$targ$0=({"assigns":0,"uses":0,"transfers":[],"replaceable":false});(stats$0[v$0]=$targ$0);(void 0);}return send(stats$0,v$0);});varstats$0=(function varstats(temp$0$0,stats$1){let t0$0;let x$0;let m$0;let m$1;let m$2;let acc$0;let temp$1;let other$0;let vars$1;let body$1;let generator$0;let vars$0;let body$0;let v$1;let v1$1;let expr$1;let v1$0;let v2$0;let $$19706$0;let $$19707$0;let $$19708$0;let $$19709$0;let $$19710$0;let $$19711$0;let $$19712$0;let $$19713$0;let $$19714$0;let t0$1;let t1$0;let t2$0;let t3$0;let t4$0;let t5$0;let expr$0;let ph$0$0;t0$0=temp$0$0;expr$0=t0$0;ph$0$0=t0$0;t0$1=ph$0$0;t1$0=t0$1.length;if((($$19708$0=(t1$0===3))&&(($$19709$0=(t0$1[0]==="assign"))&&((t2$0=t0$1[1]),(($$19711$0=Array.isArray(t2$0))&&((t3$0=t2$0.length),(($$19713$0=(t3$0===2))&&(($$19714$0=(t2$0[0]==="variable"))&&((v1$0=t2$0[1]),(t4$0=t0$1[2]),(Array.isArray(t4$0)&&((t5$0=t4$0.length),((t5$0===2)&&(t4$0[0]==="variable"))))))))))))){v2$0=t4$0[1];(s$0(stats$1,v1$0)["assigns"]=(s$0(stats$1,v1$0).assigns+1));(s$0(stats$1,v2$0)["uses"]=(s$0(stats$1,v2$0).uses+1));return s$0(stats$1,v2$0).transfers.push(v1$0);}else{if($$19714$0){v1$1=t2$0[1];expr$1=t0$1[2];(s$0(stats$1,v1$1)["assigns"]=(s$0(stats$1,v1$1).assigns+1));return varstats$0(expr$1,stats$1);}else{if(((t1$0===2)&&(t0$1[0]==="variable"))){v$1=t0$1[1];return (s$0(stats$1,v$1)["uses"]=(s$0(stats$1,v$1).uses+1));}else{if(((x$0=ph$0$0),((x$0 instanceof Array)&&(x$0[0]==="value")))){return undefined;}else{t0$1=ph$0$0;t1$0=t0$1.length;if(((t1$0===3)&&(t0$1[0]==="scope"))){vars$0=t0$1[1];body$0=t0$1[2];m$0=null;$1:for(m$0 of vars$0){let $targ$1;let v$2;let t0$2;let t1$1;t0$2=m$0;if((Array.isArray(t0$2)&&((t1$1=t0$2.length),((t1$1===2)&&(t0$2[0]==="variable"))))){v$2=t0$2[1];$targ$1=true;(s$0(stats$1,v$2)["replaceable"]=$targ$1);(void 0);}else{___match_error(m$0);}}return varstats$0(body$0,stats$1);}else{if((((t1$0>=3)&&(t1$0<=4))&&(t0$1[0]==="lambda"))){vars$1=t0$1[1];body$1=t0$1[2];if((3>=t1$0)){generator$0=null;}else{generator$0=t0$1[3];}m$1=null;$2:for(m$1 of vars$1){let v$3;let t0$3;let t1$2;t0$3=m$1;if((Array.isArray(t0$3)&&((t1$2=t0$3.length),((t1$2===2)&&(t0$3[0]==="variable"))))){v$3=t0$3[1];(s$0(stats$1,v$3)["assigns"]=(s$0(stats$1,v$3).assigns+1));}else{___match_error(m$1);}}return varstats$0(body$1,stats$1);}else{other$0=ph$0$0;acc$0=[];temp$1=null;m$2=null;$3:for(m$2 of other$0.slice(1)){let x$1;x$1=m$2;temp$1=varstats$0(x$1,stats$1);acc$0.push(temp$1);}return acc$0;}}}}}}});replaceVars$0=(function replaceVars(temp$2$0,repl$0){let t0$4;let x$2;let x$3;let m$3;let newvars$0;let m$4;let acc$1;let temp$3;let newrest$0;let other$1;let x$4;let rest$0;let vars$3;let body$3;let generator$1;let vars$2;let body$2;let v1$2;let v2$1;let v$4;let $$19876$0;let $$19877$0;let $$19878$0;let t0$5;let t1$3;let t2$1;let t3$1;let t4$1;let t5$1;let bridge$$19871$0;let expr$2;let ph$1$0;t0$4=temp$2$0;expr$2=t0$4;ph$1$0=t0$4;t0$5=ph$1$0;if((($$19877$0=Array.isArray(t0$5))&&((t1$3=t0$5.length),((t1$3===2)&&((t0$5[0]==="variable")&&((v$4=t0$5[1]),(Object.hasOwnProperty.call(repl$0,v$4)&&send(repl$0,v$4)))))))){return __lt____lt____colon__$0(["variable",send(repl$0,v$4)],expr$2);}else{if(($$19877$0&&((t1$3===3)&&((t0$5[0]==="assign")&&((t2$1=t0$5[1]),(Array.isArray(t2$1)&&((t3$1=t2$1.length),((t3$1===2)&&((t2$1[0]==="variable")&&((v1$2=t2$1[1]),(t4$1=t0$5[2]),(Array.isArray(t4$1)&&((t5$1=t4$1.length),((t5$1===2)&&((t4$1[0]==="variable")&&((v2$1=t4$1[1]),(equal(send(repl$0,v1$2),v2$1)||equal(send(repl$0,v2$1),v1$2))))))))))))))))){return __lt____lt____colon__$0(["multi"],expr$2);}else{bridge$$19871$0=ph$1$0;if((((x$2=bridge$$19871$0),((x$2 instanceof Array)&&(x$2[0]==="variable")))||((x$3=bridge$$19871$0),((x$3 instanceof Array)&&(x$3[0]==="value"))))){return expr$2;}else{t0$5=ph$1$0;t1$3=t0$5.length;if(((t1$3===3)&&(t0$5[0]==="scope"))){vars$2=t0$5[1];body$2=t0$5[2];newvars$0=[];m$3=null;$4:for(m$3 of vars$2){let _var$0;let v$5;let t0$6;let t1$4;t0$6=m$3;_var$0=t0$6;if((Array.isArray(t0$6)&&((t1$4=t0$6.length),((t1$4===2)&&(t0$6[0]==="variable"))))){v$5=t0$6[1];if(Object.hasOwnProperty.call(repl$0,v$5)){if((send(repl$0,v$5)!==false)){newvars$0.push(__lt____lt____colon__$0(["variable",send(repl$0,v$5)],_var$0));}}else{newvars$0.push(_var$0);}}else{___match_error(m$3);}}return __lt____lt____colon__$0(["scope",newvars$0,replaceVars$0(body$2,repl$0)],expr$2);}else{if((((t1$3>=3)&&(t1$3<=4))&&(t0$5[0]==="lambda"))){vars$3=t0$5[1];body$3=t0$5[2];if((3>=t1$3)){generator$1=null;}else{generator$1=t0$5[3];}return __lt____lt____colon__$0(["lambda",vars$3,replaceVars$0(body$3,repl$0),generator$1],expr$2);}else{if((t1$3>=1)){x$4=t0$5[0];rest$0=Array.prototype.slice.call(t0$5,1);acc$1=[];temp$3=null;m$4=null;$5:for(m$4 of rest$0){let elem$0;elem$0=m$4;temp$3=replaceVars$0(elem$0,repl$0);acc$1.push(temp$3);}newrest$0=acc$1;return __lt____lt____colon__$0([x$4].concat(newrest$0),expr$2);}else{other$1=ph$1$0;console.error(other$1);throw ErrorFactory(["replaceVars"]).create(("Unknown: "+String(other$1)));}}}}}}});eliminate_spurious_variables$0=(function eliminate_spurious_variables(expr$3){let m$5;let stats$2;let repl$1;stats$2=({});varstats$0(expr$3,stats$2);repl$1=({});m$5=null;$6:for(m$5 of items(stats$2)){let t0$8;let t1$6;let $targ$3;let $targ$4;let $targ$5;let $targ$6;let $targ$2;let tr$0;let st2$0;let v$6;let st$0;let t0$7;let t1$5;t0$7=m$5;if((Array.isArray(t0$7)&&((t1$5=t0$7.length),(t1$5===2)))){v$6=t0$7[0];st$0=t0$7[1];if((((equal(st$0.uses,1)&&equal(st$0.assigns,1))&&equal(st$0.transfers.length,1))&&st$0.replaceable)){$targ$2=st$0.transfers;t0$8=$targ$2;if((Array.isArray(t0$8)&&((t1$6=t0$8.length),(t1$6===1)))){tr$0=t0$8[0];}else{___match_error($targ$2,"{tr}");}st2$0=s$0(stats$2,tr$0);if((equal(st2$0.assigns,1)&&st2$0.replaceable)){$targ$3=tr$0;(repl$1[v$6]=$targ$3);$targ$4=false;(repl$1[tr$0]=$targ$4);$targ$5=false;(st$0["replaceable"]=$targ$5);$targ$6=false;(st2$0["replaceable"]=$targ$6);(void 0);}}}else{___match_error(m$5);}}return replaceVars$0(expr$3,repl$1);});hoist$0=(function hoist(expr$4){let t0$9;let t1$7;let $targ$7;let b$0;let inner$0;$targ$7=hoist_helper$0(expr$4);t0$9=$targ$7;if((Array.isArray(t0$9)&&((t1$7=t0$9.length),(t1$7===2)))){b$0=t0$9[0];inner$0=t0$9[1];}else{___match_error($targ$7,"{b, inner}");}[b$0,inner$0];return ["scope",inner$0,b$0];});hoistable$0=["send","array","object","multi","if","assign","js_break","js_continue","js_return","js_delete","js_throw","js_try","js_new","js_yield"];not_hoistable$0=["void","js_while","js_for","js_for_in","js_for_of","js_label"];hoist_helper$0=(function hoist_helper(temp$4$0){let t0$10;let x$5;let x$6;let bridge$$20130$0;let x$7;let t0$12;let t1$9;let $targ$8;let newbody$0;let inner$1;let t0$13;let t1$10;let $targ$9;let newbody$1;let inner$2;let newlambda$0;let m$6;let acc$2;let temp$5;let accum$0;let newargs$0;let m$7;let acc$3;let temp$6;let newargs$1;let other$3;let type$1;let args$1;let type$0;let args$0;let vars$5;let body$5;let generator$2;let vars$4;let body$4;let $$20136$0;let $$20137$0;let $$20138$0;let $$20139$0;let bridge$$20129$0;let t0$11;let t1$8;let expr$5;let ph$2$0;t0$10=temp$4$0;expr$5=t0$10;ph$2$0=t0$10;bridge$$20129$0=ph$2$0;if((((bridge$$20130$0=bridge$$20129$0),(((x$5=bridge$$20130$0),((x$5 instanceof Array)&&(x$5[0]==="symbol")))||((x$6=bridge$$20130$0),((x$6 instanceof Array)&&(x$6[0]==="value")))))||((x$7=bridge$$20129$0),((x$7 instanceof Array)&&(x$7[0]==="variable"))))){return [expr$5,[]];}else{t0$11=ph$2$0;t1$8=t0$11.length;if(((t1$8===3)&&(t0$11[0]==="scope"))){vars$4=t0$11[1];body$4=t0$11[2];$targ$8=hoist_helper$0(body$4);t0$12=$targ$8;if((Array.isArray(t0$12)&&((t1$9=t0$12.length),(t1$9===2)))){newbody$0=t0$12[0];inner$1=t0$12[1];}else{___match_error($targ$8,"{newbody, inner}");}[newbody$0,inner$1];return [newbody$0,inner$1.concat(vars$4)];}else{if(((t1$8===4)&&(t0$11[0]==="lambda"))){vars$5=t0$11[1];body$5=t0$11[2];generator$2=t0$11[3];$targ$9=hoist_helper$0(body$5);t0$13=$targ$9;if((Array.isArray(t0$13)&&((t1$10=t0$13.length),(t1$10===2)))){newbody$1=t0$13[0];inner$2=t0$13[1];}else{___match_error($targ$9,"{newbody, inner}");}[newbody$1,inner$2];newlambda$0=__amp____colon__(["lambda",vars$5,__lt____lt____colon__$0(["scope",inner$2,newbody$1],body$5),generator$2],({"name":expr$5.name}));return [__lt____lt____colon__$0(newlambda$0,expr$5),[]];}else{if((($$20137$0=Array.isArray(t0$11))&&((t1$8=t0$11.length),(($$20139$0=(t1$8>=1))&&((type$0=t0$11[0]),(args$0=Array.prototype.slice.call(t0$11,1)),(hoistable$0.indexOf(type$0)!==-1)))))){accum$0=[];acc$2=[];temp$5=null;m$6=null;$7:for(m$6 of args$0){let t0$14;let t1$11;let $targ$10;let b$1;let inner$3;let arg$0;arg$0=m$6;$targ$10=hoist_helper$0(arg$0);t0$14=$targ$10;if((Array.isArray(t0$14)&&((t1$11=t0$14.length),(t1$11===2)))){b$1=t0$14[0];inner$3=t0$14[1];}else{___match_error($targ$10,"{b, inner}");}[b$1,inner$3];accum$0=accum$0.concat(inner$3);temp$5=b$1;acc$2.push(temp$5);}newargs$0=acc$2;return [__lt____lt____colon__$0([type$0].concat(newargs$0),expr$5),accum$0];}else{if(($$20139$0&&((type$1=t0$11[0]),(args$1=Array.prototype.slice.call(t0$11,1)),(not_hoistable$0.indexOf(type$1)!==-1)))){acc$3=[];temp$6=null;m$7=null;$8:for(m$7 of args$1){let t0$15;let t1$12;let other$2;let t0$16;let m$8$0;let $targ$11;let b$2;let inner$4;let arg$1;arg$1=m$7;$targ$11=hoist_helper$0(arg$1);t0$15=$targ$11;if((Array.isArray(t0$15)&&((t1$12=t0$15.length),(t1$12===2)))){b$2=t0$15[0];inner$4=t0$15[1];}else{___match_error($targ$11,"{b, inner}");}[b$2,inner$4];m$8$0=inner$4;if((Array.isArray(m$8$0)&&((t0$16=m$8$0.length),(t0$16===0)))){temp$6=b$2;}else{other$2=m$8$0;temp$6=["scope",inner$4,b$2];}acc$3.push(temp$6);}newargs$1=acc$3;return [__lt____lt____colon__$0([type$1].concat(newargs$1),expr$5),[]];}else{other$3=ph$2$0;throw ErrorFactory(["syntax","illegal"]).create("Illegal node -- this should not happen.",({"node":other$3}));}}}}}});$targ$12=hoist$0;(exports["hoist"]=$targ$12);$targ$13=eliminate_spurious_variables$0;(exports["eliminate_spurious_variables"]=$targ$13);(void 0); 3 | //# sourceMappingURL=opt.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/pp.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$0;let $targ$1;let $targ$2;let $targ$3;let pr_terminus$0;let pr$0;let __lt____gt__$0;let repr$0;let escape_html$0;let quotify$0;let HTML$0;pr_terminus$0=(function pr_terminus(node$0){let r$0;let pre$0;let post$0;r$0=HTML$0(node$0,"span");pre$0=(String.fromCharCode(27)+"[?0;7y+h
");post$0=("
"+String.fromCharCode(7));return console.log(((pre$0+r$0)+post$0));});pr$0=(function pr(ph$0$0,r$1){let x$0;let n$0;let t0$0;t0$0=ph$0$0;if(getChecker(ENode)(t0$0)){n$0=t0$0;return pr_terminus$0(n$0);}else{x$0=ph$0$0;return pr_terminus$0((r$1||repr$0)(x$0));}});__lt____gt__$0=(function(temp$0$0,x$1){return pr$0(x$1);});repr$0=(function repr(){let m$1;let acc$0;let temp$1;let m$2;let acc$1;let temp$2;let other$0;let entries$0;let $$25932$0;let t0$2;let x$2;let ph$2$0;let recur$0;let t0$1;let t1$0;let t2$0;let m$0$0;m$0$0=arguments;t0$1=m$0$0.length;if((((t0$1>=1)&&(t0$1<=2))&&((t1$0=m$0$0[0]),(x$2=t1$0),(ph$2$0=t1$0),(t2$0=((1>=t0$1)?repr$0:m$0$0[1])),(typeof(t2$0)==="function")))){recur$0=t2$0;if((ph$2$0===true)){return ENode([".special",".true"],({}),"true");}else{if((ph$2$0===false)){return ENode([".special",".false"],({}),"false");}else{if((ph$2$0===null)){return ENode([".special",".nil"],({}),"null");}else{if((ph$2$0===(void 0))){return ENode([".special",".nil"],({}),"undefined");}else{if((typeof(ph$2$0)==="number")){return ENode([".num"],({}),String(x$2));}else{if((typeof(ph$2$0)==="string")){return ENode([".str"],({}),x$2);}else{t0$2=ph$2$0;if(Array.isArray(t0$2)){entries$0=t0$2;return ENode([".sequence"],({}),((acc$0=[]),(temp$1=null),(m$1=null),(function(){$0:for(m$1 of entries$0){let x$3;x$3=m$1;temp$1=recur$0(x$3,repr$0);acc$0.push(temp$1);}})(),acc$0));}else{if(x$2["::repr"]){return x$2["::repr"](recur$0);}else{if((Object.getPrototypeOf(x$2)===Object.prototype)){return ENode(["table",".object"],({}),((acc$1=[]),(temp$2=null),(m$2=null),(function(){$1:for(m$2 of items(x$2)){let k$0;let v$0;let t0$3;let t1$1;t0$3=m$2;if((Array.isArray(t0$3)&&((t1$1=t0$3.length),(t1$1===2)))){k$0=t0$3[0];v$0=t0$3[1];temp$2=ENode(["tr"],({}),[ENode(["th"],({}),recur$0(k$0,repr$0)),ENode(["td"],({}),recur$0(v$0,repr$0))]);acc$1.push(temp$2);}else{___match_error(m$2);}}})(),acc$1));}else{other$0=ph$2$0;return ENode([".unknown"],({}),other$0.toString());}}}}}}}}}}else{return ___match_error(m$0$0,"{x and match, Function? recur = repr}");}});escape_html$0=(function escape_html(temp$3$0){let t0$4;let repl$0;let s$0;t0$4=[true,String(temp$3$0)];if(t0$4[0]){s$0=t0$4[1];}else{___match_error(temp$3$0);}repl$0=({"&":"&","<":"<",">":">"});return s$0.replace(RegExp("[&<>]","g"),(function(x$4){return send(repl$0,x$4);}));});quotify$0=(function quotify(temp$4$0){let t0$5;let s$1;t0$5=[true,String(temp$4$0)];if(t0$5[0]){s$1=t0$5[1];}else{___match_error(temp$4$0);}return s$1.replace(RegExp("[\\\"\\\\]","g"),(function(x$5){return ("\\"+x$5);}));});HTML$0=(function HTML(ph$3$0,default_tag$0){let m$3;let acc$2;let temp$5;let chs$0;let m$5;let m$6;let m$7;let acc$3;let temp$6;let m$9;let acc$4;let temp$7;let m$10;let acc$5;let temp$8;let other$2;let m$8$0;let x$6;let other$3;let m$4$0;let tag$0;let classes$0;let id$0;let kv$0;let sub$0;let accum$0;let children2$0;let other$4;let tags$0;let props$0;let children$1;let children$0;let s$2;let $$26115$0;let t0$6;t0$6=ph$3$0;if((typeof(t0$6)==="string")){s$2=t0$6;return escape_html$0(s$2);}else{if(Array.isArray(t0$6)){children$0=t0$6;acc$2=[];temp$5=null;m$3=null;$2:for(m$3 of children$0){let child$0;child$0=m$3;temp$5=HTML$0(child$0,default_tag$0);acc$2.push(temp$5);}chs$0=acc$2;return chs$0.join("");}else{if((getChecker(ENode)(t0$6)&&(___hasprop(t0$6,"tags")&&((tags$0=t0$6.tags),(___hasprop(t0$6,"props")&&((props$0=t0$6.props),___hasprop(t0$6,"children"))))))){children$1=t0$6.children;tag$0=(default_tag$0||"span");classes$0=[];id$0=null;kv$0=[];sub$0=[];m$5=null;$3:for(m$5 of tags$0){let other$1;let cls$0;let t0$7;let t1$2;let t2$1;t0$7=getProjector(RegExp("^\\.(.*)",""))(m$5);if((t0$7[0]&&((t1$2=t0$7[1]),(t2$1=t1$2.length),(t2$1===2)))){t1$2[0];cls$0=t1$2[1];classes$0.push(cls$0);}else{other$1=m$5;tag$0=other$1;tag$0;}}m$6=null;$4:for(m$6 of items(props$0)){let k$1;let v$1;let t0$8;let t1$3;t0$8=m$6;if((Array.isArray(t0$8)&&((t1$3=t0$8.length),(t1$3===2)))){k$1=t0$8[0];v$1=t0$8[1];kv$0.push([k$1,v$1]);}else{___match_error(m$6);}}if((tag$0==="raw")){accum$0=[];}else{accum$0=["<",tag$0];}if(id$0){accum$0=accum$0.concat(" id=\"",id$0,"\"");accum$0;}if(classes$0.length){accum$0=accum$0.concat(" class=\"",quotify$0(classes$0.join(" ")),"\"");accum$0;}if(kv$0){acc$3=[];temp$6=null;m$7=null;$5:for(m$7 of kv$0){let k$2;let v$2;let t0$9;let t1$4;t0$9=m$7;if((Array.isArray(t0$9)&&((t1$4=t0$9.length),(t1$4===2)))){k$2=t0$9[0];v$2=t0$9[1];accum$0=accum$0.concat(((v$2!==null)?[" ",k$2,"=\"",quotify$0(v$2),"\""]:[" ",k$2]));temp$6=accum$0;acc$3.push(temp$6);}else{___match_error(m$7);}}acc$3;}m$8$0=tag$0;if((m$8$0==="raw")){acc$4=[];temp$7=null;m$9=null;$6:for(m$9 of children$1){let c$0;let s$3;let t0$10;t0$10=m$9;if((typeof(t0$10)==="string")){s$3=t0$10;temp$7=s$3;acc$4.push(temp$7);}else{c$0=m$9;temp$7=HTML$0(c$0,default_tag$0);acc$4.push(temp$7);}}children2$0=acc$4;}else{other$2=m$8$0;acc$5=[];temp$8=null;m$10=null;$7:for(m$10 of children$1){let c$1;c$1=m$10;temp$8=HTML$0(c$1,default_tag$0);acc$5.push(temp$8);}children2$0=acc$5;}m$4$0=tag$0;if((m$4$0==="raw")){return accum$0.concat(children2$0).join("");}else{other$3=m$4$0;x$6=[">"].concat(children2$0).concat([""]);return accum$0.concat(x$6).join("");}}else{other$4=ph$3$0;return HTML$0([true,String(other$4)][1],default_tag$0);}}}});$targ$0=pr_terminus$0;(exports["pr_terminus"]=$targ$0);$targ$1=pr$0;(exports["pr"]=$targ$1);$targ$2=__lt____gt__$0;(exports["<>"]=$targ$2);$targ$3=repr$0;(exports["repr"]=$targ$3);(void 0); 3 | //# sourceMappingURL=pp.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/register.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$0;let $targ$1;let $targ$6;let $targ$7;let fs$0;let path$0;let sm$0;let $1$0;let version$0;let getCache$0;let load$0;let extensions$0;let install$0;fs$0=require("fs");path$0=require("path");sm$0=require("source-map-support");$1$0=require("./version");version$0=getProperty($1$0,"version","./version");if((typeof(module)==="undefined")){$targ$0=undefined;(global["module"]=$targ$0);(void 0);}if((typeof(JSON)==="undefined")){$targ$1=undefined;(global["JSON"]=$targ$1);(void 0);}sm$0.install();getCache$0=(function getCache(){let rval$0;let rval$1;let bridge$$26554$0;let eg$0;let $3$0;let Source$0;let text$0;let g$1;let $targ$3;let code$0;let map$0;let t0$1;let t1$0;let cachedir$0;let cache$0;let cacheoptsFile$0;let sstat$0;let cstat$0;let cacheopts$0;let newcacheopts$0;let $targ$2;let g$0;let compiled$0;let srcfile$0;let file$0;let opts$0;let t0$0;let m$0$0;m$0$0=arguments;t0$0=m$0$0.length;if(((t0$0>=1)&&(t0$0<=2))){file$0=m$0$0[0];if((1>=t0$0)){opts$0=({});}else{opts$0=m$0$0[1];}cachedir$0=path$0.join(path$0.dirname(file$0),"egcache");cache$0=path$0.join(cachedir$0,path$0.basename(file$0).replace(RegExp(".eg$|$",""),".js"));cacheoptsFile$0=cache$0.replace(RegExp(".js$|$",""),".json");sstat$0=fs$0.statSync(file$0);rval$0=false;try{rval$0=fs$0.statSync(cache$0);rval$0;}catch(excv$0){let e$0;e$0=excv$0;rval$0=null;rval$0;}cstat$0=rval$0;rval$1=false;try{rval$1=JSON.parse(fs$0.readFileSync(cacheoptsFile$0,"utf8"));rval$1;}catch(excv$1){let e$1;e$1=excv$1;rval$1=null;rval$1;}cacheopts$0=rval$1;newcacheopts$0=({"versions":({"ecmascript":(opts$0["es5"]?5:6),"earlgrey":version$0}),"runtime":opts$0.runtime,"parameters":(opts$0.parameters||({}))});if((((((!opts$0.recompile)&&(!opts$0.interactive))&&equal(cacheopts$0,newcacheopts$0))&&cstat$0)&&(sstat$0.mtime.getTime() code, => map} or code and map is null");}[code$0,map$0];try{try{fs$0.mkdirSync(cachedir$0);}catch(excv$2){let e$2;e$2=excv$2;"ignore error";}fs$0.writeFileSync(cache$0,code$0);fs$0.writeFileSync((cache$0+".map"),map$0);fs$0.writeFileSync(cacheoptsFile$0,JSON.stringify(newcacheopts$0));}catch(excv$3){let e$3;e$3=excv$3;console.error(("Failed to cache compiled version of: "+file$0));}$targ$2=[g$1,code$0,cache$0];}t0$1=$targ$2;if((Array.isArray(t0$1)&&((t1$0=t0$1.length),(t1$0===3)))){g$0=t0$1[0];compiled$0=t0$1[1];srcfile$0=t0$1[2];}else{___match_error($targ$2,"{g, compiled, srcfile}");}[g$0,compiled$0,srcfile$0];return [g$0,compiled$0,srcfile$0];}else{return ___match_error(m$0$0,"{file, opts = {=}}");}});load$0=(function load(opts$1){return (function(module$0,file$1){let t0$2;let t1$1;let $targ$4;let compiled$1;let srcfile$1;$targ$4=getCache$0(file$1,opts$1);t0$2=$targ$4;if((Array.isArray(t0$2)&&((t1$1=t0$2.length),(t1$1===3)))){t0$2[0];compiled$1=t0$2[1];srcfile$1=t0$2[2];}else{___match_error($targ$4,"{_, compiled, srcfile}");}[compiled$1,srcfile$1];return module$0._compile(compiled$1,srcfile$1);});});extensions$0=[".eg"];install$0=(function install(){let xreg$0;let m$2;let acc$0;let temp$0;let req$0;let opts$2;let t0$3;let m$1$0;m$1$0=arguments;t0$3=m$1$0.length;if(((t0$3>=0)&&(t0$3<=1))){if((0>=t0$3)){opts$2=({"recompile":false,"runtime":null});}else{opts$2=m$1$0[0];}req$0=require;if(((xreg$0=req$0.extensions),xreg$0)){acc$0=[];temp$0=null;m$2=null;$4:for(m$2 of extensions$0){let $targ$5;let ext$0;ext$0=m$2;if((!send(xreg$0,ext$0))){$targ$5=load$0(opts$2);(xreg$0[ext$0]=$targ$5);temp$0=(void 0);}acc$0.push(temp$0);}return acc$0;}}else{return ___match_error(m$1$0,"{opts = {recompile = false, runtime = null}}");}});$targ$6=getCache$0;(exports["getCache"]=$targ$6);$targ$7=install$0;(exports["install"]=$targ$7);(void 0); 3 | //# sourceMappingURL=register.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/stdenv.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $24$0;let $26$0;let $28$0;let $30$0;let $32$0;let $34$0;let $36$0;let $38$0;let $40$0;let $42$0;let $44$0;let $targ$0;let $targ$1;let mt$0;let Env$0;let Expander$0;let topscope$0;let stdenv$0;let mac$0;let bind$0;let make_expander$0;mt$0=require("./expand");Env$0=getProperty(mt$0,"Env","mt");Expander$0=getProperty(mt$0,"Expander","mt");topscope$0=getProperty(mt$0,"topscope","mt");stdenv$0=Env$0();mac$0=(function mac(name$0){return (function(m$0){let m2$0;m2$0=(function m2(ctx$0,info$0,form$0,temp$0$0){let t0$0;let t0$1;let expr$0;let ph$0$0;t0$0=temp$0$0;expr$0=t0$0;ph$0$0=t0$0;t0$1=ph$0$0;if((___hasprop(t0$1,"brackets")&&(t0$1.brackets==="()"))){throw ErrorFactory(["syntax","no_parens"]).create("Parentheses cannot be used here.\n Use [] or {} depending on your intent.\n []s are usually equivalent to an absence\n of brackets.\n ".replace(RegExp("\\n *","g")," "),({"expr":expr$0}));}else{return m$0.call(this,ctx$0,info$0,form$0,expr$0);}});stdenv$0.bind(topscope$0,name$0,["macro",m2$0]);return m2$0;});});bind$0=(function bind(name$1,value$0){return stdenv$0.bind(topscope$0,name$1,value$0);});(($24$0=require("./macros/consts")),$24$0)(mac$0,bind$0);(($26$0=require("./macros/core")),$26$0)(mac$0,bind$0);(($28$0=require("./macros/operators")),$28$0)(mac$0,bind$0);(($30$0=require("./macros/loop")),$30$0)(mac$0,bind$0);(($32$0=require("./macros/quote")),$32$0)(mac$0,bind$0);(($34$0=require("./macros/regexp")),$34$0)(mac$0,bind$0);(($36$0=require("./macros/modularity")),$36$0)(mac$0,bind$0);(($38$0=require("./macros/misc")),$38$0)(mac$0,bind$0);(($40$0=require("./macros/macrodef")),$40$0)(mac$0,bind$0);(($42$0=require("./macros/async")),$42$0)(mac$0,bind$0);(($44$0=require("./macros/logic")),$44$0)(mac$0,bind$0);make_expander$0=(function make_expander(pipeline$0){let generic_nodes$0;generic_nodes$0=["if","js_while","js_for","js_for_in","js_for_of","js_label","js_break","js_continue","js_return","js_delete","js_throw","js_try","js_new","js_yield"];return Expander$0(stdenv$0.fork(),generic_nodes$0,pipeline$0);});$targ$0=stdenv$0;(exports["stdenv"]=$targ$0);$targ$1=make_expander$0;(exports["make_expander"]=$targ$1);(void 0); 3 | //# sourceMappingURL=stdenv.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/util.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let f$2;let f$3;let f$4;let f$5;let f$6;let f$7;let f$8;let $targ$4;let $targ$5;let $targ$6;let $targ$7;let $targ$8;let $targ$9;let $targ$10;let $targ$11;let $targ$12;let $targ$13;let $targ$14;let $targ$15;let $targ$16;let $targ$17;let GenSym$0;let gensym$0;let identity$0;let binsearch$0;let classify$0;let classify_contiguous$0;let partition$0;let construct$0;let mkset$0;let Body$0;let camelCase$0;let invCamelCase$0;let mac1$0;let __chk_ncache$0;let __chk_scache$0;let checker_db$0;GenSym$0=(function GenSym(prefix$0){let id$0;id$0=0;return (function(){let r$0;let pfx$0;let t0$0;let m$0$0;m$0$0=arguments;t0$0=m$0$0.length;if(((t0$0>=0)&&(t0$0<=1))){if((0>=t0$0)){pfx$0="";}else{pfx$0=m$0$0[0];}r$0=((pfx$0+prefix$0)+[true,String(id$0)][1]);(id$0++);return r$0;}else{return ___match_error(m$0$0,"{pfx = \"\"}");}});});gensym$0=GenSym$0("$$");identity$0=(function identity(x$0){return x$0;});binsearch$0=(function binsearch(xs$0,x$1){let lo$0;let hi$0;lo$0=0;hi$0=(xs$0.length-1);$0:while((lo$0<=hi$0)){let m$1$0;let mid$0;let v$0;mid$0=(lo$0+((hi$0-lo$0)>>1));v$0=send(xs$0,mid$0);m$1$0=send(xs$0,mid$0);if((m$1$0x$1)){hi$0=(mid$0-1);hi$0;}else{return (mid$0+1);}}}return lo$0;});classify$0=(function classify(){let m$3;let results$0;let xs$1;let classes$0;let t0$1;let m$2$0;m$2$0=arguments;t0$1=m$2$0.length;if((t0$1>=1)){classes$0=Array.prototype.slice.call(m$2$0,0,-1);xs$1=m$2$0[(t0$1-1)];results$0=({"rest":[]});m$3=null;$1:for(m$3 of classes$0){let $targ$0;let cls$0;cls$0=m$3;$targ$0=[];(results$0[cls$0]=$targ$0);(void 0);}$2:while(xs$1.length){let x$2;let other$0;let cls$1;let x$3;let newxs$0;let t0$2;let m$4$0;m$4$0=xs$1.shift();if((Array.isArray(m$4$0)&&((t0$2=m$4$0.length),((t0$2>=1)&&(m$4$0[0]==="splice"))))){newxs$0=Array.prototype.slice.call(m$4$0,1);xs$1=newxs$0.concat(xs$1);xs$1;}else{if(((x$2=m$4$0),((x$2 instanceof Array)&&(x$2[0]==="ignore")))){null;}else{if((Array.isArray(m$4$0)&&((t0$2=m$4$0.length),((t0$2===2)&&((cls$1=m$4$0[0]),(x$3=m$4$0[1]),send(results$0,cls$1)))))){send(results$0,cls$1).push(x$3);}else{other$0=m$4$0;results$0.rest.push(other$0);}}}}return results$0;}else{return ___match_error(m$2$0,"{*classes, var xs}");}});classify_contiguous$0=(function classify_contiguous(xs$2,classifier$0){let m$5;let groups$0;let currcls$0;let curr$0;groups$0=[];currcls$0=null;curr$0=null;m$5=null;$3:for(m$5 of xs$2){let cls$2;let x$4;x$4=m$5;cls$2=classifier$0(x$4);if((cls$2===currcls$0)){curr$0.push(x$4);}else{if(curr$0){groups$0.push(curr$0);}curr$0=[cls$2,x$4];currcls$0=cls$2;currcls$0;}}if(curr$0){groups$0.push(curr$0);}return groups$0;});partition$0=(function partition(xs$3,predicate$0){let m$6;let t$0;let f$0;t$0=[];f$0=[];m$6=null;$4:for(m$6 of xs$3){let x$6;let x$5;x$5=m$6;if(predicate$0(x$5)){t$0.push(x$5);}else{x$6=m$6;f$0.push(x$6);}}return [t$0,f$0];});construct$0=(function construct(ph$0$0,fn$0,zero$0){let x$8;let rest$0;let x$7;let $$30888$0;let $$30889$0;let t0$3;let t1$0;t0$3=ph$0$0;t1$0=t0$3.length;if((t1$0===0)){return zero$0;}else{if((t1$0===1)){x$7=t0$3[0];return x$7;}else{if((t1$0>=1)){x$8=t0$3[0];rest$0=Array.prototype.slice.call(t0$3,1);return fn$0(x$8,construct$0(rest$0,fn$0,zero$0));}else{return ___match_error(ph$0$0,"{x, *rest}");}}}});mkset$0=(function mkset(xs$4){let m$7;let rval$0;rval$0=({});m$7=null;$5:for(m$7 of xs$4){let $targ$1;let x$9;x$9=m$7;$targ$1=true;(rval$0[x$9]=$targ$1);(void 0);}return rval$0;});Body$0=(function Body(temp$0$0){let t0$4;let xs$5;let t0$5;let t1$1;let x$10;let ph$1$0;t0$4=temp$0$0;x$10=t0$4;ph$1$0=t0$4;t0$5=ph$1$0;t1$1=t0$5.length;if(((t1$1>=1)&&(t0$5[0]==="multi"))){xs$5=Array.prototype.slice.call(t0$5,1);return xs$5;}else{return [x$10];}});camelCase$0=(function camelCase(x$11){if(equal(x$11.indexOf("-"),-1)){return x$11;}else{return x$11.replace(RegExp("-([A-Za-z0-9_])","g"),(function(temp$1$0,m$8){return m$8.toUpperCase();}));}});invCamelCase$0=(function invCamelCase(x$12){return x$12.replace(RegExp("([a-z0-9])([A-Z]+)","g"),(function(temp$2$0,m1$0,m2$0){return ((m1$0+"-")+m2$0.toLowerCase());}));});mac1$0=(function mac1(){let f$1;let name$0;let t0$6;let m$9$0;m$9$0=arguments;t0$6=m$9$0.length;if(((t0$6>=1)&&(t0$6<=2))){f$1=m$9$0[0];if((1>=t0$6)){name$0=null;}else{name$0=m$9$0[1];}return ["macro",(function(context$0,scope$0,form$0,ph$2$0){let expr$0;let $$31017$0;let t0$7;let t1$2;t0$7=ph$2$0;t1$2=t0$7.length;if(((t1$2===2)&&(t0$7[0]==="data"))){expr$0=t0$7[1];return f$1(expr$0);}else{if((Array.isArray(t0$7)&&((t1$2=t0$7.length),((t1$2===1)&&((t0$7[0]==="void")&&name$0))))){return ["variable",name$0];}else{return ___match_error(ph$2$0,"#void{} when name");}}})];}else{return ___match_error(m$9$0,"{f, name = null}");}});__chk_ncache$0=({});__chk_scache$0=({});checker_db$0=(function checker_db(ph$3$0){let v$1;let $targ$2;let v$2;let $targ$3;let s$0;let n$0;let $$31061$0;let t0$8;if((ph$3$0===null)){return checker_db$0.null;}else{if((ph$3$0===(void 0))){return checker_db$0.undefined;}else{if((ph$3$0===true)){return checker_db$0.true;}else{if((ph$3$0===false)){return checker_db$0.false;}else{t0$8=ph$3$0;if((typeof(t0$8)==="number")){n$0=t0$8;if(send(__chk_ncache$0,n$0)){return send(__chk_ncache$0,n$0);}else{v$1=mac1$0((function(x$13){return ["send",["symbol","==="],["data",x$13,["value",n$0]]];}));$targ$2=v$1;(__chk_ncache$0[n$0]=$targ$2);return v$1;}}else{if((typeof(t0$8)==="string")){s$0=t0$8;if(Object.prototype.hasOwnProperty.call(__chk_scache$0,s$0)){return send(__chk_scache$0,s$0);}else{v$2=mac1$0((function(x$14){return ["send",["symbol","==="],["data",x$14,["value",s$0]]];}));$targ$3=v$2;(__chk_scache$0[s$0]=$targ$3);return v$2;}}else{return ___match_error(ph$3$0,"String? s");}}}}}}});__amp____colon__(checker_db$0,({"String":((f$2=(function f(x$15){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$15]],["value","string"]]];})),mac1$0(f$2,"String")),"Number":((f$3=(function f(x$16){return ["send",["symbol","==="],["data",["send",["symbol","typeof"],["data",x$16]],["value","number"]]];})),mac1$0(f$3,"Number")),"Array":((f$4=(function f(x$17){return ["send",["send",["symbol","Array"],["send",["symbol","."],["data",["void"],["symbol","isArray"]]]],["data",x$17]];})),mac1$0(f$4,"Array")),"true":((f$5=(function f(x$18){return x$18;})),mac1$0(f$5,"true")),"false":((f$6=(function f(x$19){return ["send",["symbol","not"],["data",["void"],x$19]];})),mac1$0(f$6,"false")),"null":((f$7=(function f(x$20){return ["send",["symbol","==="],["data",x$20,["value",null]]];})),mac1$0(f$7,"null")),"undefined":((f$8=(function f(x$21){return ["send",["symbol","==="],["data",x$21,["value",undefined]]];})),mac1$0(f$8,"undefined"))}));$targ$4=GenSym$0;(exports["GenSym"]=$targ$4);$targ$5=gensym$0;(exports["gensym"]=$targ$5);$targ$6=identity$0;(exports["identity"]=$targ$6);$targ$7=binsearch$0;(exports["binsearch"]=$targ$7);$targ$8=classify$0;(exports["classify"]=$targ$8);$targ$9=classify_contiguous$0;(exports["classify_contiguous"]=$targ$9);$targ$10=partition$0;(exports["partition"]=$targ$10);$targ$11=construct$0;(exports["construct"]=$targ$11);$targ$12=mkset$0;(exports["mkset"]=$targ$12);$targ$13=Body$0;(exports["Body"]=$targ$13);$targ$14=camelCase$0;(exports["camelCase"]=$targ$14);$targ$15=invCamelCase$0;(exports["invCamelCase"]=$targ$15);$targ$16=mac1$0;(exports["mac1"]=$targ$16);$targ$17=checker_db$0;(exports["checker_db"]=$targ$17);(void 0); 3 | //# sourceMappingURL=util.js.map 4 | 5 | -------------------------------------------------------------------------------- /bootstrap/version.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict';require('earlgrey-runtime/6');let $targ$0;let package$1;let version$0;package$1=require("../package");version$0=getProperty(package$1,"version","package");$targ$0=version$0;(exports["version"]=$targ$0);(void 0); 3 | //# sourceMappingURL=version.js.map 4 | 5 | -------------------------------------------------------------------------------- /examples/bottle.eg: -------------------------------------------------------------------------------- 1 | 2 | bottle{match} = 3 | 0 -> "no more bottles" 4 | 1 -> "one bottle" 5 | n -> '{n} bottles' 6 | 7 | action{match} = 8 | 0 -> "Go to the store and buy some more," 9 | n -> "Take one down and pass it around," 10 | 11 | capitalize{s} = 12 | s[0].toUpperCase{} + s.substring{1} 13 | 14 | 0..99 each i -> 15 | n = 99 - i 16 | print '{capitalize{bottle{n}}} of beer on the wall, {bottle{n}} of beer.' 17 | print '{action{n}} {bottle{[n + 99] mod 100}} of beer on the wall.' 18 | print "" 19 | -------------------------------------------------------------------------------- /examples/even.eg: -------------------------------------------------------------------------------- 1 | 2 | predicate! even{x} = x mod 2 == 0 3 | predicate! odd{x} = x mod 2 == 1 4 | 5 | floor_even{match} = 6 | even? x -> x 7 | odd? x -> x - 1 8 | x -> floor_even{Math.floor{x}} 9 | 10 | print { 11 | even? 4 12 | even? 5 13 | floor_even{7} 14 | floor_even{13.5} 15 | } 16 | -------------------------------------------------------------------------------- /examples/fact.eg: -------------------------------------------------------------------------------- 1 | 2 | fact{match} = 3 | 0 -> 1 4 | n -> n * fact{n - 1} 5 | 6 | print fact{15} 7 | -------------------------------------------------------------------------------- /examples/fib.eg: -------------------------------------------------------------------------------- 1 | 2 | fib{match} = 3 | 0 -> 0 4 | 1 -> 1 5 | n -> fib{n - 1} + fib{n - 2} 6 | 7 | print fib{30} 8 | -------------------------------------------------------------------------------- /examples/macros.eg: -------------------------------------------------------------------------------- 1 | 2 | 3 | ;; Unless 4 | 5 | inline-macro unless{#data{test, body}}: 6 | `if{not ^test, ^body}` 7 | 8 | unless 0: 9 | print "yes" 10 | 11 | 12 | ;; A fancy way of writing while [1]: ... :) 13 | 14 | inline-macro forever{#data{body}}: 15 | ;; The label is needed in order for the user to be able 16 | ;; to break/continue from forever. Without the label, EG 17 | ;; considers that the while loop is not visible from the 18 | ;; user's lexical scope, so break ought to skip past it. 19 | ;; However, if there's a label, EG will look at the its 20 | ;; environment to determine the whole while loop's 21 | ;; visibility. @mark{label} will stamp our freshly 22 | ;; created label with the environment where forever was 23 | ;; used :) 24 | lbl = @mark{#value{@gensym{}}} 25 | `while[^lbl]{1, ^body}` 26 | 27 | 1..4 each i -> 28 | forever: 29 | print "let's not be too crazy and break out while we still can!" 30 | break ;; comment out the lbl= line and you'll see the above is only printed once 31 | 32 | 33 | ;; Define the ~ operator to define anonymous functions, with the 34 | ;; variable $ holding the first argument 35 | 36 | inline-macro [~]{#data{#void{}, body}}: 37 | dolla = @mark{`$`} 38 | `{^dolla} -> ^body` 39 | 40 | add10 = ~[$ + 10] 41 | first4 = ~$.substring{0, 4} 42 | 43 | print { 44 | add10{91} 45 | first4{"hello"} 46 | } 47 | -------------------------------------------------------------------------------- /examples/operators.eg: -------------------------------------------------------------------------------- 1 | 2 | ;; Function composition 3 | [f1 @@ f2]{x} = f1{f2{x}} 4 | 5 | f{x} = x + 1.5 6 | g{x} = x / 2 7 | h{x} = 3 ** x 8 | 9 | ;; I have yet to provide hooks to define precedence rules 10 | fgh = f @@ [g @@ h] 11 | 12 | print 1..10 each i -> fgh{i} 13 | 14 | 15 | ;; Let's swap some variables! 16 | inline-macro [<=>]{*, #data{a, b}}: 17 | ``` 18 | let temp = ^a 19 | ^a = ^b 20 | ^b = temp 21 | ``` 22 | 23 | var x = 10 24 | var y = 20 25 | print {x, y} 26 | 27 | x <=> y 28 | print {x, y} 29 | 30 | var temp = 60 31 | temp <=> x 32 | print {x, temp} 33 | 34 | 35 | ;; Besides their predefined priority, there's really nothing special 36 | ;; about the standard operators 37 | print { 38 | 10 + 4 / 8 39 | 10 + 4 / 8 where 40 | a + b = a - b 41 | a / b = a * b 42 | } 43 | -------------------------------------------------------------------------------- /examples/statemachine.eg: -------------------------------------------------------------------------------- 1 | 2 | 3 | inline-macro statemachine{#data{name, #multi! #multi{*fns}}}: 4 | ;; This macro will help us define state machines nicely and easily 5 | 6 | ;; Usage: 7 | ;; statemachine name{*constructor_args} = 8 | ;; initial_state{*args} = 9 | ;; ... 10 | ;; switch .other_state 11 | ;; ... 12 | ;; other_state{*args} = 13 | ;; ... 14 | ;; ... 15 | ;; sm = name{*constructor_args} 16 | ;; sm{*args} 17 | ;; sm{*other_args} 18 | ;; ... 19 | 20 | ;; Arguments of the macro: 21 | ;; context, scope: we won't need them here 22 | ;; form: a reference to the whole macro call 23 | ;; #data{name, #multi! {*fns}}: this will match something like 24 | ;; statemachine{name, [fn1, fn2, ...]}, or something like 25 | ;; statemachine name: 26 | ;; fn1 27 | ;; ... 28 | 29 | ;; First we create variables named "state" and "switch" which will 30 | ;; be visible in the user's lexical environment 31 | ;; form.env should contain a reference to that environment 32 | state = @mark{`state`} 33 | switch = @mark{`switch`} 34 | 35 | ;; We scrape the name of the initial state from the first clause 36 | `[^ #symbol{initial_state}][^_] = ^_` = 37 | fns[0] 38 | 39 | ;; We define switch as a macro so that we don't need {}s or with 40 | ;; switch newstate ==> state = newstate 41 | switch_macro{*, newstate} = 42 | `^state = ^newstate` 43 | 44 | ;; #splice shouldn't actually be needed here, I'll have to check 45 | ;; what's going on with this. Anyway, it works. 46 | #splice with 47 | ``` 48 | ^name = 49 | ^[#declare_raw{switch, #macro{switch_macro}}] 50 | states = {^* fns} 51 | var ^state = ^=initial_state 52 | {*args} -> 53 | states[^state].apply{null, args} 54 | ``` 55 | 56 | 57 | statemachine Safe{key, var prize}: 58 | ;; Exercise: add the #put action :) 59 | 60 | locked{*match} = 61 | #lock -> 62 | #unlock{== key} -> 63 | switch .unlocked 64 | #unlock -> 65 | throw E.safe.wrong_key{} 66 | #open -> 67 | throw E.safe.locked{} 68 | #close -> 69 | #take -> 70 | throw E.safe.closed{} 71 | 72 | unlocked{*match} = 73 | #lock -> 74 | switch .locked 75 | #unlock -> 76 | #open -> 77 | switch .open 78 | #close -> 79 | #take -> 80 | throw E.safe.closed{} 81 | 82 | open{*match} = 83 | #lock -> 84 | throw E.safe.open{} 85 | #unlock -> 86 | #open -> 87 | #close -> 88 | switch .unlocked 89 | #take when prize -> 90 | print "Took " + [String! prize] + "!" 91 | prize = null 92 | #take -> 93 | print "The safe is empty!" 94 | 95 | 96 | safe = Safe{"secret", "a million dollars"} 97 | 98 | safe #unlock{"secret"} 99 | safe #open 100 | safe #take 101 | safe #take 102 | 103 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "earlgrey", 3 | "version": "0.1.2", 4 | "description": "Programming language compiling to JavaScript, featuring macros, dynamic typing annotations and pattern matching.", 5 | "main": "./6.js", 6 | "dependencies": { 7 | "babel-core": "^6.9.0", 8 | "babel-preset-es2015": "^6.9.0", 9 | "del": "^2.2.0", 10 | "earlgrey-runtime": "^0.1.0", 11 | "js-beautify": "^1.6.2", 12 | "mkdirp": "^0.5.1", 13 | "multi-stage-sourcemap": "^0.2.1", 14 | "opg": ">=0.0.5", 15 | "source-map": "^0.5.6", 16 | "source-map-support": "^0.4.0" 17 | }, 18 | "devDependencies": { 19 | "mocha": "^2.2.1", 20 | "earl-mocha": ">=0.0.3" 21 | }, 22 | "bin": { 23 | "earl": "bin/earl", 24 | "earl5": "bin/earl5" 25 | }, 26 | "scripts": { 27 | "prepublish": "bin/bootstrap 2 && bin/bootstrap -5 2", 28 | "test": "earl clean test && mocha" 29 | }, 30 | "homepage": "http://breuleux.github.io/earl-grey/repl", 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/breuleux/earl-grey" 34 | }, 35 | "engines": { 36 | "node": ">=4.0.0" 37 | }, 38 | "keywords": [ 39 | "earlgrey", 40 | "language", 41 | "macros", 42 | "pattern-matching" 43 | ], 44 | "author": "Olivier Breuleux", 45 | "license": "MIT" 46 | } 47 | -------------------------------------------------------------------------------- /register.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | 4 | if (parseInt(process.version.split(".")[0].slice(1)) >= 4 5 | || process.title == "iojs") { 6 | require("./lib6/register").install({es5: false, lazy: true, runtime: null}); 7 | } 8 | else { 9 | require("./lib5/register").install({es5: true, lazy: true, runtime: null}); 10 | } 11 | -------------------------------------------------------------------------------- /src/README: -------------------------------------------------------------------------------- 1 | 2 | Source code organization 3 | ------------------------ 4 | 5 | location.eg 6 | Defines the Source and Location classes and a bunch of utility 7 | functions for highlighting. 8 | 9 | lex.eg 10 | Defines the lexer. 11 | lex.tokenize{Source} ==> list of tokens 12 | 13 | parse.eg 14 | Operator precedence parsing. 15 | Note that the following simplifications are applied in this phase: 16 | * "a with b" ==> a{b} 17 | * "foo bar: baz" ==> foo{bar, baz} 18 | parse.parse{tokens} ==> raw AST (unexpanded) 19 | 20 | expand.eg 21 | Defines the Scope, Env and Expander classes, which are the basis of 22 | the macro expander. Core behavior like symbol resolution and 23 | expansion of #multi and #data nodes are here. 24 | 25 | stdenv.eg 26 | Defines most core macros and control structures. 27 | * if, while, break, class, each, etc. 28 | * Whitelist of global variables. 29 | * Contains the code for a few required shims (e.g. Array.prototype["::check"]) 30 | 31 | pattern.eg 32 | Most of the code pertaining to pattern matching is here. 33 | 34 | translate-js.eg 35 | Defines Translator, which takes an expanded AST and produces 36 | JavaScript code. 37 | 38 | earl-grey.eg 39 | Glues all the parts together in a coherent interface, Generator. 40 | 41 | run.eg 42 | Defines the command-line interface of the earl utility. 43 | Entry point is the run function. 44 | 45 | register.eg 46 | Import to register earl grey as an extension. 47 | 48 | 49 | util.eg 50 | Miscellaneous utilities. 51 | 52 | opt.eg 53 | Defines the hoist function, a minor optimization. 54 | 55 | pp.eg 56 | Pretty-printing, to be removed (probably). 57 | 58 | 59 | Notes 60 | ----- 61 | 62 | AST nodes are plain arrays, so you won't find a formal definition 63 | anywhere. Essentially: 64 | 65 | Core nodes (produced by parse.parse): 66 | #symbol{String?} ==> symbol 67 | #value{v} ==> literals (numbers, strings, etc.) 68 | #multi{...} ==> [a, b, ...] (at least two elements in []s) 69 | #data{...} ==> {...} 70 | #send{obj, msg} ==> function calls, field accesses, etc. 71 | 72 | Processed nodes (produced during macro expansion in addition to core nodes): 73 | #array{...} ==> create an array 74 | #object{#array{k1, v1}, ...} ==> create an object from key/value pairs 75 | #if{test, x, y} ==> conditionals 76 | #scope{vars, body} ==> variable declaration 77 | #lambda{args, body} ==> function definition 78 | #js_while, #js_for, etc. ==> javascript-specific control structures 79 | 80 | Temporary nodes/expansion control 81 | #macro{fn} ==> `fn` will be used to expand #send{#macro{fn}, arg} 82 | #nostep{macro} ==> Defer macro expansion to later 83 | (macro expansion may happen in multiple contexts) 84 | #parse{str, url} ==> Instruct EG's expander to parse the code string 85 | (useful to implement interpolation in strings) 86 | -------------------------------------------------------------------------------- /src/earl-grey.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./location" -> 4 | Source, Location 5 | highlight_locations 6 | <<: 7 | "./lex" -> 8 | tokenize 9 | "./parse" -> 10 | parse 11 | "./translate-js" -> 12 | Translator 13 | "./stdenv" as std 14 | "./expand" as exp 15 | "./opt" as opt 16 | "./util" -> 17 | Body 18 | GenSym 19 | vm, module, path 20 | "source-map" as smap -> 21 | SourceNode 22 | "multi-stage-sourcemap" -> transfer 23 | "./version" -> version 24 | "./evaluator" -> evaluator 25 | 26 | provide: 27 | evaluator 28 | Source, Location, highlight_locations 29 | tokenize, parse 30 | Generator 31 | version 32 | compile 33 | 34 | 35 | es5Transform{x, opts = {=}} = 36 | require: 37 | babel-core 38 | babel-preset-es2015 39 | babel-core.transform{ 40 | x 41 | opts & { 42 | babelrc = false 43 | compact = true 44 | presets = {babel-preset-es2015} 45 | } 46 | } 47 | 48 | 49 | 50 | globalizer = GenSym{"_$$_"} 51 | 52 | class Pipeline: 53 | 54 | constructor{@opts} = 55 | @gensym = globalizer 56 | @_expander = std.make_expander{@} 57 | @env = @_expander.mkenv{} 58 | 59 | parse{source} = 60 | t = tokenize{source} 61 | parse{t} 62 | 63 | expand{ast} = 64 | @_expander.expand{#top, exp.topscope, @env.mark{ast}} 65 | 66 | translate{ast} = 67 | res = opt.hoist{ast} 68 | globvar = @gensym{"global"} 69 | tr = Translator{null, globvar} 70 | rval = collapse{tr.translate{res, .expr}} 71 | prep = tr.dump_store{} 72 | { 73 | code = 74 | if @opts.es5: 75 | es5Transform{r}.code 76 | else: 77 | r 78 | globvar = globvar 79 | global = Object.create{global} 80 | location = ast.location 81 | } where 82 | r = "\"use strict\";" + prep + ";(" + rval + ")" 83 | 84 | evaluate{src} = 85 | url = src.location??.source??.url 86 | ev{src.code} where 87 | ev = evaluator with { 88 | globvar = src.globvar 89 | global = src.global 90 | filename = url or "" 91 | showname = url or "" 92 | cwd = url 93 | } 94 | 95 | go{x, match start, end} = 96 | when start === end or start === .eval -> 97 | x 98 | .source -> 99 | @go{@parse{x}, .parse, end} 100 | .parse -> 101 | @go{@expand{x}, .expand, end} 102 | .expand -> 103 | @go{@translate{x}, .translate, end} 104 | .translate -> 105 | @go{@evaluate{x}, .eval, end} 106 | else -> 107 | throw E.pipeline{"Unknown pipeline stage: " + start} 108 | 109 | 110 | collapse{match node} = 111 | ENode? {=> tags, => props, => children} -> 112 | parts = {} 113 | acc{children} where acc{match} = 114 | String? s -> parts.push with s 115 | Array? [each x] -> acc{x} 116 | ENode? n -> parts.push with collapse{n} 117 | parts.join{""} 118 | String? s -> 119 | s 120 | else -> 121 | print node 122 | throw E.invalid_translation_node{node} 123 | 124 | makeAnnotatedAST{match node} = 125 | ENode? {=> tags, => props, => children} -> 126 | parts = {} 127 | acc{children} where acc{match} = 128 | String? s -> parts.push with s 129 | Array? [each x] -> acc{x} 130 | ENode? n -> parts.push with makeAnnotatedAST{n} 131 | 132 | if props.origin and props.origin.location: 133 | loc = props.origin.location 134 | {{var l, var c}, _} = loc.linecol{} 135 | src = loc.source.url 136 | rval = new SourceNode{l, c, src or "", parts} 137 | ;; print {l, c, loc.text{}, rval.toStringWithSourceMap{{=}}.code} 138 | rval 139 | else: 140 | parts 141 | String? s -> 142 | s 143 | else -> 144 | print node 145 | throw E.invalid_translation_node{node} 146 | 147 | toCodeAndSourceMap{node, url} = 148 | var ast = makeAnnotatedAST{node} 149 | if not SourceNode? ast: 150 | ast = new SourceNode{1, 0, null, ast} 151 | obj = ast.toStringWithSourceMap with {file = url} 152 | obj 153 | 154 | 155 | class Generator: 156 | 157 | constructor{@opts = {=}} = 158 | if @opts.runtime === undefined: 159 | @opts.runtime = "earlgrey-runtime" 160 | require: "./register" -> install{@opts} 161 | @tr = Translator{null, @opts.globvar} 162 | @env = std.stdenv.fork{} 163 | items{@opts.parameters or {=}} each {k, v} -> 164 | @env.setopt{exp.topscope, k, v} 165 | @interactive = @opts.interactive 166 | if @interactive: @opts.runtime = null 167 | @_eval = null 168 | use-es6 = 169 | match process.title: 170 | .node -> parseInt{process.version.split{"."}[0].slice{1}} >= 4 171 | .iojs -> true 172 | else -> false 173 | @pipeline = Pipeline{{es5 = not use-es6} & @opts} 174 | @expander = std.make_expander{@pipeline} 175 | 176 | generateInteractive{source, var opts = {=}} = 177 | 178 | opts = @opts & opts 179 | 180 | t = tokenize{source} 181 | p = parse{t} 182 | ;; #interactive forces declarations into the top scope, which 183 | ;; means successive calls to generate{} will see global 184 | ;; variables set by the previous. It also makes all variables 185 | ;; declared in the top scope mutable (because that's more 186 | ;; practical in interactive mode) 187 | var ex = @expander.expand{ 188 | #top 189 | opts.scope or exp.topscope 190 | @env.mark{stmt} 191 | } where stmt = 192 | if @interactive: 193 | then: 194 | Body! {*args} = p 195 | #interactive{*args} 196 | else: #multi{p} 197 | 198 | wrap{body} = 199 | #send{#variable{.spawn}, #array{#lambda{{}, body, #value{true}}}} 200 | 201 | ex = match ex: 202 | #scope{vars, body} -> 203 | #scope{vars, wrap{body}} 204 | body -> 205 | wrap{body} 206 | 207 | ex = opt.hoist{ex} 208 | 209 | var result = @tr.translate{ex, .stmt} 210 | result = splice % 211 | "\n'use strict';" 212 | match opts.runtime: 213 | null? -> "" 214 | rt when opts.es5 -> 215 | "require('" + rt + "/5');" 216 | rt -> 217 | "require('" + rt + "/6');" 218 | result 219 | result = collapse{result} 220 | 221 | if opts.es5: 222 | result = es5Transform{result, {=}}.code 223 | 224 | result 225 | 226 | 227 | generate{source, var opts = {=}} = 228 | 229 | opts = @opts & opts 230 | 231 | t = tokenize{source} 232 | p = parse{t} 233 | ;; #interactive forces declarations into the top scope, which 234 | ;; means successive calls to generate{} will see global 235 | ;; variables set by the previous. It also makes all variables 236 | ;; declared in the top scope mutable (because that's more 237 | ;; practical in interactive mode) 238 | var ex = @expander.expand{ 239 | #top 240 | opts.scope or exp.topscope 241 | @env.mark{stmt} 242 | } where stmt = 243 | if @interactive: 244 | then: 245 | Body! {*args} = p 246 | #interactive{*args} 247 | else: #multi{p} 248 | ex = opt.hoist{ex} 249 | ;; set ex = opt.eliminate_spurious_variables{ex} 250 | 251 | var result = @tr.translate{ex, .stmt} 252 | result = splice % 253 | "\n'use strict';" 254 | match opts.runtime: 255 | null? -> "" 256 | rt when opts.es5 -> 257 | "require('" + rt + "/5');" 258 | rt -> 259 | "require('" + rt + "/6');" 260 | @tr.dump_store{} ;; useless at this point I think 261 | result 262 | 263 | if not opts.sourceMap: 264 | result = collapse{result} 265 | if opts.es5: 266 | result = es5Transform{result, {=}}.code 267 | {code = result, map = null} 268 | 269 | else: 270 | 271 | result = toCodeAndSourceMap{result, source.url} 272 | 273 | if opts.es5: 274 | {=> code, => map} = es5Transform{result.code, {source-maps = true}} 275 | newmap = transfer with { 276 | fromSourceMap = map 277 | toSourceMap = result.map.toString{} 278 | } 279 | 280 | result = {code = code, map = newmap} 281 | 282 | match opts.sourceMap: 283 | .inline -> 284 | result.code 285 | \ + "\n/"+"/# sourceMappingURL=data:application/json;base64," 286 | \ + [new Buffer{result.map.toString{}}.toString{.base64}] 287 | \ + ".map\n" 288 | .compute -> 289 | result 290 | else -> 291 | parts = source.url.split{"/"} 292 | smname = parts[parts.length - 1].replace{R".eg$", ".js"} 293 | result.code += 294 | "\n/" + "/# sourceMappingURL=" + smname + ".map\n" 295 | result 296 | 297 | getEval{file} = 298 | if [not @_eval]: 299 | @_eval = evaluator with { 300 | globvar = @tr.globvar 301 | global = null 302 | filename = file 303 | showname = file 304 | cwd = file 305 | } 306 | @_eval 307 | 308 | evaluate{source} = 309 | @getEval{source.url}{@generate{source, {runtime = null}}.code} 310 | 311 | evaluateInteractive{source, opts = {=}} = 312 | @getEval{source.url}{@generateInteractive{source, opts & {runtime = null}}} 313 | 314 | 315 | compile{match source, options = {=}} = 316 | String? -> 317 | Generator{options}.generate{Source{source, options.path or ""}} 318 | Source? -> 319 | Generator{options}.generate{source} 320 | 321 | -------------------------------------------------------------------------------- /src/evaluator.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | module 4 | path 5 | vm 6 | 7 | provide: 8 | evaluator 9 | 10 | evaluator{options} = 11 | 12 | req = require 13 | 14 | glob = 15 | if options.globvar: 16 | match global[options.globvar]: 17 | undefined? -> 18 | gl = 19 | match options.global: 20 | === true -> 21 | global 22 | Object? g -> 23 | g 24 | else -> 25 | Object.create{global} 26 | ;; _glob = {=} 27 | ;; for v in global: 28 | ;; _glob[v] = global[v] 29 | ;; _glob 30 | global[options.globvar] = gl 31 | gl 32 | g -> g 33 | else: 34 | global 35 | 36 | if module._nodeModulePaths: 37 | paths = if{options.cwd, module._nodeModulePaths{options.cwd}, {}} 38 | 39 | e_module = new module{options.showname} 40 | e_module &: { 41 | filename = options.filename 42 | paths = paths 43 | } 44 | 45 | e_require{path} = 46 | module._load{path, e_module, true} 47 | e_require &: { 48 | main = e_module 49 | resolve{path} = 50 | module._resolveFileName{path, e_module} 51 | paths = paths 52 | cache = req.cache 53 | } 54 | 55 | setup = { 56 | __filename = options.filename 57 | __dirname = path.dirname{options.filename} 58 | module = e_module 59 | require = e_require 60 | exports = {=} 61 | } 62 | 63 | glob &: setup 64 | 65 | {code} -> 66 | script = vm.createScript{code, options.showname} 67 | rval = script.runInThisContext{} 68 | rval 69 | 70 | else: 71 | __eval = eval 72 | {code} -> __eval{code} 73 | -------------------------------------------------------------------------------- /src/location.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./util" -> 4 | binsearch ;;, items, enumerate 5 | "./pp" -> 6 | <>, repr as _repr 7 | fs 8 | opg -> 9 | Source, Location 10 | "opg/lib/highlight" -> 11 | highlight as highlight 12 | highlightLocations as highlight_locations 13 | mergeLocations as merge_locations 14 | 15 | provide: 16 | Source, Location 17 | highlight, highlight_locations 18 | merge_locations 19 | <<:, ++: 20 | format_error, display_error 21 | 22 | let repr = _repr 23 | 24 | 25 | 26 | x <<: y = 27 | if [not Location? x.location]: 28 | x.location = if{not y or Location? y, y, y.location} 29 | if y.called: x.called = y.called 30 | if y.name: x.name = y.name 31 | x 32 | 33 | x ++: y = 34 | x2 = if{not x or Location? x, x, x.location} 35 | y2 = if{not y or Location? y, y, y.location} 36 | [merge_locations with {x2, y2}] !! e -> undefined 37 | 38 | 39 | 40 | format_error{match e, context = 0} = 41 | 42 | do: 43 | fmt_args{e} = 44 | if [e.args and e.args.length]: 45 | then: .error_args % repr{e.args} 46 | else: "" 47 | 48 | E.syntax? {args => {args}} -> 49 | hls = {.hl1, .hl2, .hl3, .hl4} 50 | locs = enumerate{items{args}} each 51 | {i, {key, arg}} when arg and arg.location -> 52 | {arg.location, hls[i mod 4]} 53 | div % 54 | .error % 55 | .error_type % e.name 56 | .error_message % e.message 57 | .error_args.syntax % repr{args} 58 | highlight_locations{locs, context} 59 | 60 | {location => Location? loc} -> 61 | div % 62 | .error % 63 | .error_type % e.name 64 | .error_message % e.message 65 | fmt_args{e} 66 | highlight_locations{{{loc, .hl1}}, context} 67 | .traceback % e.stack or "" 68 | 69 | {location => #location{url, start, end}} -> 70 | data = fs.readFileSync{url, .utf8} !! e -> null 71 | if data: 72 | then: 73 | loc = Location{Source{data, url}, start, end} 74 | div % 75 | .error % 76 | .error_type % e.name 77 | .error_message % e.message 78 | fmt_args{e} 79 | ;; if{e.args, .error_args % repr{e.args}, ""} 80 | highlight_locations{{{loc, .hl1}}, context} 81 | .traceback % 82 | % e.stack or "" 83 | else: 84 | div % 85 | .error % 86 | .error_type % e.name 87 | .error_message % e.message 88 | fmt_args{e} 89 | .traceback % 90 | % e.stack or e 91 | 92 | other -> 93 | div % 94 | .error % 95 | .error_type % e.name 96 | .error_message % e.message 97 | ;; if e.args: 98 | ;; then: .error_args % repr{e.args} 99 | ;; else: "" 100 | fmt_args{e} 101 | .traceback % 102 | % e.stack 103 | 104 | display_error{e} = 105 | <> format_error{e} 106 | 107 | -------------------------------------------------------------------------------- /src/macros/async.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./helpers" -> 4 | expr_mac, expr_mac2 5 | AssignmentHandler 6 | 7 | inject: mac 8 | 9 | 10 | mac{"yield"}! yield_mac{match, _, form, arg} = 11 | #pattern -> 12 | #special{AssignmentHandler{subp, w}} where 13 | subp = if{arg == #void{}, null, arg} 14 | w{ph} = `yield ^ph` 15 | #expr{.expr} or #expr{.head} -> 16 | match arg: 17 | `all[^arg]` -> #js_yield{arg, #value{true}} 18 | arg -> #js_yield{arg, #value{false}} 19 | otherwise -> 20 | #nostep{form} 21 | 22 | mac{"await"}! await_mac{match, _, form, arg} = 23 | #pattern -> 24 | #special{AssignmentHandler{subp, w}} where 25 | subp = if{arg == #void{}, null, arg} 26 | w{ph} = `await ^ph` 27 | #expr{.expr} or #expr{.head} -> 28 | match arg: 29 | `all[^arg]` -> #js_yield{`Promise.all{^arg}`, #value{false}} 30 | `any[^arg]` -> #js_yield{`Promise.race{^arg}`, #value{false}} 31 | arg -> #js_yield{arg, #value{false}} 32 | otherwise -> 33 | #nostep{form} 34 | 35 | 36 | mac{"gen"}! gen_mac{match, info, form, expr} = 37 | when expr == #void{} -> 38 | #nostep{form} 39 | #pattern -> 40 | #project{#macro{mac}, expr, true} where mac{*blah, #data{match e}} = 41 | #use{env, x} -> 42 | #use{env, mac.call{this, #data{x}}} 43 | `^arg -> ^body` -> 44 | `^arg *-> ^body` 45 | `_lambda{^arg, ^pre, ^body, ^post, ^_}` -> 46 | ;; TODO: this is wrong; post should be inside the spawn 47 | `_lambda{^arg, ^pre, ^body, ^post, ^=true}` 48 | else -> 49 | throw E.syntax.gen{"gen must decorate a function", {node = e}} 50 | match is expr -> 51 | `{^arg -> ^body}` or `^arg -> ^body` -> 52 | `^arg *-> ^body` 53 | `{_lambda{^arg, ^pre, ^body, ^post, ^_}}` -> 54 | ;; TODO: this is wrong; post should be inside the spawn 55 | `_lambda{^arg, ^pre, ^body, ^post, ^=true}` 56 | else -> 57 | throw E.syntax.gen{"gen must be applied on a function", {expr = expr}} 58 | 59 | mac{"async"}! async_mac{match, info, form, expr} = 60 | when expr == #void{} -> 61 | #nostep{form} 62 | #pattern -> 63 | #project{#macro{mac}, expr, true} where mac{*blah, #data{match e}} = 64 | #use{env, x} -> 65 | #use{env, mac.call{this, #data{x}}} 66 | `^arg -> ^body` -> 67 | `^arg -> spawn.call{this, {} *-> ^body}` 68 | `_lambda{^arg, ^pre, ^body, ^post, ^_}` -> 69 | ;; TODO: this is wrong; post should be inside the spawn 70 | `_lambda{^arg, ^pre, spawn.call{this, {} *-> ^body}, ^post, ^=false}` 71 | else -> 72 | throw E.syntax.async{"async must decorate a function", {node = e}} 73 | match is expr -> 74 | `{^arg -> ^body}` or `^arg -> ^body` -> 75 | `^arg -> spawn.call{this, {} *-> ^body}` 76 | `{_lambda{^arg, ^pre, ^body, ^post, ^_}}` -> 77 | ;; TODO: this is wrong; post should be inside the spawn 78 | `_lambda{^arg, ^pre, spawn.call{this, {} *-> ^body}, ^post, ^=false}` 79 | `{^x}` or x -> 80 | `spawn.call{this, {} *-> [try{await ^x}, catch{e, console.error{e.stack}}]}` 81 | 82 | 83 | mac{"eager-await"}! eager_await_mac{ctx, _, form, expr} = 84 | ``` 85 | match ^expr: 86 | Promise? p -> await p 87 | x -> x 88 | ``` 89 | 90 | mac{"eager-async"}! eager_async_mac{match, info, form, expr} = 91 | do: 92 | aw = info.mark{`await`} 93 | wrap{body} = 94 | ``` 95 | inline-macro [^aw]{expr}: `eager-await ^expr` 96 | ^body 97 | ``` 98 | when expr == #void{} -> 99 | #nostep{form} 100 | #pattern -> 101 | #project{#macro{mac}, expr, true} where mac{*blah, #data{match e}} = 102 | #use{env, x} -> 103 | #use{env, mac.call{this, #data{x}}} 104 | `^arg -> ^body` -> 105 | `^arg -> spawn.call{this, {} *-> ^wrap{body}, true}` 106 | `_lambda{^arg, ^pre, ^body, ^post, ^_}` -> 107 | ;; TODO: this is wrong; post should be inside the spawn 108 | `_lambda{^arg, ^pre, spawn.call{this, {} *-> ^wrap{body}, true}, ^post, ^=false}` 109 | else -> 110 | throw E.syntax.async{"async must decorate a function", {node = e}} 111 | match is expr -> 112 | `{^arg -> ^body}` or `^arg -> ^body` -> 113 | `^arg -> spawn.call{this, {} *-> ^wrap{body}, true}` 114 | `{_lambda{^arg, ^pre, ^body, ^post, ^_}}` -> 115 | ;; TODO: this is wrong; post should be inside the spawn 116 | `_lambda{^arg, ^pre, spawn.call{this, {} *-> ^wrap{body}, true}, ^post, ^=false}` 117 | `{^x}` or x -> 118 | `spawn.call{this, {} *-> [try{await ^x}, catch{e, console.error{e.stack}}], true}` 119 | 120 | -------------------------------------------------------------------------------- /src/macros/consts.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./helpers" -> 4 | protected_value 5 | value_mac 6 | 7 | 8 | inject: 9 | mac, bind 10 | 11 | 12 | global_variables = { 13 | "!=" 14 | "!==" 15 | "&" 16 | "&+" 17 | "&:" 18 | "*" 19 | "+" 20 | "++" 21 | "-" 22 | "--" 23 | "/" 24 | "<" 25 | "<<" 26 | "<=" 27 | "==" 28 | "===" 29 | ">" 30 | ">=" 31 | ">>" 32 | ">>>" 33 | "^+" 34 | "|+" 35 | .___build_array 36 | .___extend 37 | .___hasprop 38 | .___js_fetch 39 | .___match_error 40 | .___node 41 | .___serialize_ast 42 | .__dirname 43 | .__filename 44 | .and 45 | .arguments 46 | .Array 47 | .ArrayBuffer 48 | .Buffer 49 | .clearImmediate 50 | .clearInterval 51 | .clearTimeout 52 | .clone 53 | .console 54 | .consume 55 | .contains 56 | .DataView 57 | .Date 58 | .decodeURI 59 | .decodeURIComponent 60 | .dir 61 | .encodeURI 62 | .encodeURIComponent 63 | .ENode 64 | .enumerate 65 | .equal 66 | .Error 67 | .ErrorFactory 68 | .eval 69 | .EvalError 70 | .exports 71 | .Float32Array 72 | .Float64Array 73 | .Function 74 | .getChecker 75 | .getProjector 76 | .getProperty 77 | .global 78 | .in 79 | .Infinity 80 | .instanceof 81 | .Int16Array 82 | .Int32Array 83 | .Int8Array 84 | .Intl 85 | .isFinite 86 | .isNaN 87 | .items 88 | .JSON 89 | .keys 90 | .Map 91 | .Math 92 | .mod 93 | .module 94 | .NaN 95 | .neighbours 96 | .nequal 97 | .not 98 | .Object 99 | .object 100 | .or 101 | .parseFloat 102 | .parseInt 103 | .predicate 104 | .process 105 | .product 106 | .Promise 107 | .promisify 108 | .Proxy 109 | .range 110 | .RangeError 111 | .ReferenceError 112 | .Reflect 113 | .RegExp 114 | .repr 115 | .send 116 | .Set 117 | .setImmediate 118 | .setInterval 119 | .setTimeout 120 | .spawn 121 | .Symbol 122 | .SyntaxError 123 | .super 124 | .take 125 | .this 126 | .TypeError 127 | .typeof 128 | .Uint16Array 129 | .Uint32Array 130 | .Uint8Array 131 | .Uint8ClampedArray 132 | .URIError 133 | .WeakMap 134 | .WeakSet 135 | .zip 136 | } 137 | 138 | global_variables each gvar -> 139 | bind{gvar, #variable{gvar} & {mutable = false, assigned = true}} 140 | 141 | keywords = { 142 | true = protected_value{.true, true} 143 | false = protected_value{.false, false} 144 | null = protected_value{.null, null} 145 | undefined = protected_value{.undefined, undefined} 146 | pass = #variable{.undefined} 147 | } 148 | 149 | items{keywords} each {gvar, v} -> 150 | bind{gvar, v} 151 | 152 | [items{kv} each {k, v} -> mac{k}{v}] where kv = { 153 | "null" = value_mac{.null, chk} where 154 | chk{x} = `^x === ^=null` 155 | "undefined" = value_mac{.undefined, chk} where 156 | chk{x} = `^x === ^=undefined` 157 | "true" = value_mac{.true, chk} where 158 | chk{x} = `if{^x, true, false}` 159 | "false" = value_mac{.false, chk} where 160 | chk{x} = `not ^x` 161 | "String" = value_mac{.String, chk, proj} where 162 | chk{x} = `typeof{^x} === .string` 163 | proj{x} = `{true, String{^x}}` 164 | "Number" = value_mac{.Number, chk, proj} where 165 | chk{x} = `typeof{^x} === .number` 166 | proj{x} = `{true, parseFloat{^x}}` 167 | "Boolean" = value_mac{.Boolean, chk, proj} where 168 | chk{x} = `typeof{^x} === .boolean` 169 | proj{x} = `{true, Boolean{^x}}` 170 | "Array" = value_mac{.Array, chk, proj} where 171 | chk{x} = `Array.isArray{^x}` 172 | proj{x} = `{true, [t = ^x, if{Array.isArray{t}, t, {t}}]}` 173 | "Function" = value_mac{.Function, chk} where 174 | chk{x} = `typeof{^x} === .function` 175 | } 176 | 177 | -------------------------------------------------------------------------------- /src/macros/core.eg: -------------------------------------------------------------------------------- 1 | 2 | 3 | require: 4 | "../util" -> 5 | camelCase 6 | "../location" -> 7 | <<: 8 | "./helpers" -> 9 | expr_mac 10 | pattern_handlers 11 | ctx_mac 12 | named_statement_matcher 13 | flatmacro 14 | match_error 15 | Body 16 | AssignmentHandler 17 | "../pattern" -> 18 | PatternCompiler 19 | parse_clauses 20 | 21 | 22 | inject: mac 23 | 24 | 25 | mac{"var"}! var_mac{#pattern, _, form, argument} = 26 | #mode{.var, argument} 27 | 28 | mac{"set-var"}! setvar_mac{#pattern, _, form, argument} = 29 | #mode{.set, argument} 30 | 31 | mac{"let"}! let_mac{match, _, form, argument} = 32 | #pattern -> 33 | #mode{.let, argument} 34 | other -> 35 | match argument: 36 | #data{Body! {*bindings}, body} -> 37 | construct{match} = 38 | {} -> body 39 | {`^bind = ^val`, *xs} -> 40 | #multi{`let ^bind = ^val`, construct{xs}} & {nonrecursive = true} 41 | construct{bindings} 42 | 43 | expr_mac! mac{"letrec"}! letrec_mac{_, form, #data{Body! {*bindings}, body}} = 44 | #multi{*let_bindings, body} where 45 | let_bindings = bindings each `^b = ^v` -> `let ^b = ^v` 46 | 47 | mac{"where"}! where_mac{context, _, form, #data{body, bindings}} = 48 | `letrec{^bindings, ^body}` 49 | 50 | mac{"raw-symbol"}! rawsym_mac{context, info, form, #data{sym and #symbol{name}}} = 51 | sym.env.mark{#raw-symbol{name}} 52 | 53 | mac{"."}! dot_mac{context, _, form, #data{#void{}, expr}} = 54 | f{expr} where f{match} = 55 | #symbol{camelCase! x} -> 56 | #value{x} 57 | #data{*args} -> 58 | #data{*[args each arg -> f{arg}]} 59 | other -> 60 | throw E.syntax.dot{"Argument to '.' must be a symbol or an array" 61 | {argument = other}} 62 | 63 | mac{"as"}! as_mac{ctx, info, form, #data{rhs, lhs}} = 64 | `^lhs = ^rhs` 65 | 66 | mac{"="}! equal_mac{match, info, form, expr} = 67 | 68 | #pattern -> 69 | #data{lhs, rhs} = expr 70 | #default{lhs, rhs} 71 | 72 | #expr{.data} -> 73 | match expr: 74 | #void{} -> 75 | #assoc{} 76 | #data{x and #symbol{s}, #void{}} 77 | \ or #data{#void{}, x and #symbol{s}} -> 78 | #assoc{#value{camelCase{s}}, x} 79 | #data{#symbol{s}, rhs} -> 80 | ;; special case for the most common situation 81 | #assoc{#value{camelCase{s}}, rhs} 82 | #data{lhs, rhs} -> 83 | #objsplice with #multi with 84 | PatternCompiler{lhs, info, opt}.extract_from_rhs{rhs2} where 85 | opt = pattern_handlers.build_object 86 | rhs2 = #use{info.scope, rhs} <<: rhs 87 | 88 | other -> 89 | match expr: 90 | ;; #data{lhs and sym and #symbol{s}, rhs} -> 91 | ;; gid = info.gensym{"G"} 92 | ;; decl = #declare{info.mark{sym}, #use{info.scope, rhs} &: {group_id = gid}} & 93 | ;; {mutable = false, use_previous = true, group_id = gid, env = info.env} 94 | ;; #splice{decl, sym} 95 | 96 | #data{lhs, rhs} -> 97 | pc = PatternCompiler{lhs, info, opt} where 98 | opt = pattern_handlers.declare_variables 99 | assignment = pc.extract_from_rhs{rhs2} where 100 | rhs2 = #use{info.scope, rhs} <<: rhs 101 | rval = match pc.vars: 102 | {} -> 103 | #value{undefined} 104 | {v} -> 105 | ;; match rhs2: #use{_, x} or x -> x &: {name = v[1]} 106 | v 107 | vs -> #data{*vs} 108 | pc.wrapAssignment{expr} where 109 | expr = #splice{assignment, rval} 110 | 111 | mac{"=>"}! fat_arrow_mac{match, {=> env}, _, #data{lhs, rhs}} = 112 | #pattern -> 113 | match {lhs, rhs}: 114 | {#void, rhs} -> 115 | #assoc{rhs} 116 | else -> 117 | #assoc{lhs, rhs} 118 | #test -> 119 | Body! {*stmts} = rhs 120 | #blocktest{lhs, stmts} 121 | other -> 122 | #assoc{lhs, rhs} 123 | 124 | mac{"_lambda"}! _lambda_mac{context, info, form, match} = 125 | #data{[arg and #data{*args} 126 | \ or #multi{*args} and arg is #data{*args} 127 | \ or #void{} and args is {} and arg is #data{} 128 | \ or arg is #data{arg} and args is {arg}] 129 | pre, body, post, generator = #value{false}} -> 130 | wrap{body2} = 131 | if{pre == #value{null}, body3, #multi{pre, body3}} where 132 | body3 = if{post == #value{null}, body2, #multi{body2, post}} 133 | 134 | pc = PatternCompiler{arg, info} with 135 | pattern_handlers.declare_variables & { 136 | indexable = true 137 | allow_nested = true 138 | fallback{target, pattern} = 139 | match_error{target, pattern} 140 | tags = {declare_mode = .let} 141 | insert_object_argument = true 142 | } 143 | cpattern = pc.compile{} 144 | 145 | match cpattern: 146 | #array_pattern{fw, {}, {}, undefined?} -> 147 | decls = {} 148 | newargs = zip{fw, args} each {match, arg} -> 149 | #assign{expr and [#symbol{v} or #variable{v}]} 150 | \ when expr.declare_mode != .set -> 151 | match expr.declare_mode: 152 | .let -> expr &: {mutable = false} 153 | .var -> expr &: {mutable = true} 154 | .unqualified or undefined? -> 155 | expr &: {mutable = false} 156 | other -> 157 | newv = #symbol{info.gensym{.temp}} & { 158 | env = info.mkenv{} 159 | location = arg.location 160 | } 161 | pc2 = pc.fork{other} 162 | decls.push with pc2.extract_from_rhs{newv} 163 | newv 164 | _body = pc.wrapBody{body} 165 | #lambda{newargs, wrap{#multi{*decls, _body}}, generator} 166 | 167 | objp and #object_pattern -> 168 | #lambda{{}, wrap{body2}, generator} where 169 | body2 = `match arguments[0]: ^arg -> ^body` 170 | 171 | #all{#array_pattern{fw, bw, defaults, rest}, objp} and {insertion_index => i} -> 172 | a = `arguments` <<: arg 173 | fw.splice{i, 0, objp} 174 | pc2 = pc.fork{newp} where 175 | newp = #array_pattern{fw, bw, defaults, rest} 176 | #lambda{{}, wrap{body2}, generator} where 177 | body2 = #multi{pc2.extract_from_rhs{a} 178 | pc.wrapBody{body}} 179 | 180 | other -> 181 | a = `arguments` <<: arg 182 | #lambda{{}, wrap{body2}, generator} where 183 | body2 = `match.indexable [^a]: ^arg -> ^body` 184 | 185 | mac{"*->"}! genarrow_mac{ctx, _, form, match} = 186 | #data{args, body} -> 187 | `_lambda{^args, ^=null, ^body, ^=null, ^=true}` 188 | other -> 189 | throw E.syntax.lambda{"Bad lambda syntax", {node = other}} 190 | 191 | mac{"@->"}! metharrow_mac{ctx, info, form, #data{args, body}} = 192 | {at, self} = info.mark{`@`, `self`} 193 | `_lambda{^args, [let ^at and ^self = this], ^body, ^=null}` 194 | 195 | mac{"->"}! arrow_mac{match, _, form, expr} = 196 | ;; do: 197 | ;; match expr: 198 | ;; `{^_, ^{brackets => ""}}` -> 199 | ;; throw E.syntax.fix{"->", expr = form} 200 | ;; else -> 201 | ;; pass 202 | #clause -> 203 | #data{lhs, rhs} = expr 204 | #clause{lhs, rhs} 205 | other -> 206 | match expr: 207 | #data{args, body} -> 208 | `_lambda{^args, ^=null, ^body, ^=null}` 209 | other -> 210 | throw E.syntax.lambda{"Bad lambda syntax", {node = other}} 211 | 212 | 213 | try_pattern = #seq{#multiple{_catch}, #multiple{_finally, 0, 1}} where 214 | _catch = named_statement_matcher{.catch} 215 | _finally = named_statement_matcher{.finally} 216 | 217 | mac{"try"}! try_mac{#expr{.multi}, info, form, #data{body}} = 218 | flatmacro{try_pattern} with 219 | {#seq{#multiple{*catches}, #multiple{*finallies}}} -> 220 | env = info.mkenv{} 221 | clauses = {} 222 | var finally = #void{} 223 | catches each `catch{^p, ^body}` -> 224 | clauses.push with 225 | env.mark with `^p -> ^body` 226 | finallies each `finally{^body}` -> 227 | finally = body 228 | clauses.push with 229 | env.mark{`e -> throw e`} 230 | make_ebody{wrap} = 231 | parse_clauses with 232 | info, `excv`, clauses 233 | {wrap = wrap} 234 | #macro{m} where ctx_mac! m{match, e} = 235 | #expr{.multi} -> 236 | #nostep{this.form} 237 | #expr{.ignore} -> 238 | #js_try{body, `{excv} -> ^make_ebody{{x} -> x}`, finally} 239 | #expr{.expr} -> 240 | trystmt = #js_try{ 241 | `set-var rval = ^body` 242 | ```{excv} -> ^make_ebody{{x} -> `set-var rval = ^x`}``` 243 | finally 244 | } 245 | `[var rval = false 246 | ^trystmt 247 | rval]` 248 | 249 | mac{"!!"}! tryop_mac{match, info, form, #data{expr, Body! {*clauses}}} = 250 | #expr{.multi} -> 251 | #nostep{form} 252 | #expr{.ignore} -> 253 | clauses.push with 254 | info.mkenv{}.mark{`e -> throw e`} 255 | parsed_clauses = 256 | parse_clauses with 257 | info, `excv`, clauses 258 | {wrap = {x} -> x} 259 | #js_try{expr, `{excv} -> ^parsed_clauses`, #void{}} 260 | other -> 261 | clauses.push with 262 | info.mkenv{}.mark{`e -> throw e`} 263 | parsed_clauses = 264 | parse_clauses with 265 | info, `excv`, clauses 266 | {wrap = {x} -> `set-var rval = ^x`} 267 | trystmt = #js_try{`set-var rval = ^expr`, `{excv} -> ^parsed_clauses`, #void{}} 268 | `let [var rval = false]: [^trystmt, rval]` 269 | 270 | expr_mac! mac{"throw"}! throw_mac{_, form, arg} = 271 | #js_throw{arg} 272 | 273 | mac{"expr-value"}! exprvalue_mac{match, _, form, arg} = 274 | #pattern -> 275 | #special{AssignmentHandler{subp, w}} where 276 | subp = if{arg == #void{}, null, arg} 277 | w{ph} = ph 278 | 279 | mac{"return"}! return_mac{match, _, form, arg} = 280 | #pattern -> 281 | #special{AssignmentHandler{subp, w}} where 282 | subp = if{arg == #void{}, null, arg} 283 | w{ph} = `return ^ph` 284 | #expr{.expr} or #expr{.head} -> 285 | #js_return{arg} 286 | otherwise -> 287 | #nostep{form} 288 | 289 | expr_mac! mac{"new"}! new_mac{_, form, arg} = 290 | #js_new{arg} 291 | 292 | mac{"delete"}! delete_mac{context, _, form, match arg} = 293 | #symbol{s} -> 294 | #undeclare{arg} 295 | other -> 296 | #js_delete{other} 297 | 298 | mac{"splice"}! splice_mac{context, _, form, #data{Body! {*stmts}}} = 299 | #splice{*stmts} 300 | 301 | mac{"#"}! hash_mac{context, _, form, #data{#void{}, #symbol{var tag}}} = 302 | set-var tag = #value{tag} 303 | #macro{f} where f{match, _, form, expr} = 304 | #pattern -> 305 | checker_mac = #macro with {context, _, form, #data{expr}} -> 306 | ```let [x = ^expr]: [[instanceof]{x, Array} and x[0] === ^tag]``` 307 | match expr: 308 | #data{*subp} -> `{^tag, ^*subp}` 309 | #void{} -> #check{checker_mac, #ignore{}} 310 | other -> #check{checker_mac, expr} 311 | #check -> 312 | `getChecker{{^tag}}` 313 | #project -> 314 | `getProjector{{^tag}}` 315 | _ -> 316 | match expr: 317 | #void{} -> 318 | `{^tag}` 319 | #data{*args} -> 320 | `{^tag, ^*args}` 321 | other -> 322 | `{^tag}[^other]` 323 | 324 | mac{"_"}! placeholder_mac{#pattern, _, form, #void{}} = 325 | #ignore{} 326 | 327 | 328 | 329 | -------------------------------------------------------------------------------- /src/macros/logic.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "../location" -> 4 | <<: 5 | "./helpers" -> 6 | accum_flags 7 | match_error 8 | Body 9 | named_statement_matcher 10 | flatmacro 11 | "../pattern" -> 12 | parse_clauses 13 | "../util" as util 14 | 15 | 16 | inject: mac 17 | 18 | 19 | class MatchHandler: 20 | 21 | constructor{} = 22 | @wrapOrder = 1 23 | 24 | expand{info} = 25 | @placeholder = info.env.mark{#symbol{info.gensym{.ph}}} 26 | @placeholder <<: @location 27 | 28 | wrap{expr, info, opt} = 29 | parse_clauses with 30 | info, @placeholder, Body{expr}, opt & {wrap = null} 31 | 32 | 33 | 34 | accum_flags! mac{"match"}! match_mac{match, info, form, expr, flags} = 35 | #pattern -> 36 | match expr: 37 | #void{} -> #special{MatchHandler{} <<: form} <<: form 38 | other -> #all{other <<: expr, #special{MatchHandler{} <<: form} <<: form} 39 | other -> 40 | opt = util.mkset{flags} 41 | to_match = #symbol{info.gensym{.m}} & {single_assignment = true} 42 | {value, body} = match expr: 43 | #data{Body! {*b}} -> {#value{null}, b} 44 | #data{v, Body! {*b}} -> {v, b} 45 | to_match <<: value 46 | `let [^to_match = ^value]: ^mbody` where mbody = 47 | parse_clauses with 48 | info, to_match, body 49 | opt & { 50 | fallback{target, pattern} = 51 | match_error{target, pattern} 52 | wrap = null 53 | } 54 | 55 | if_pattern = #seq{#multiple{_elif}, #multiple{_else, 0, 1}} where 56 | _elif = named_statement_matcher{.elif} 57 | _else = named_statement_matcher{.else} 58 | 59 | mac{"if"}! if_mac{ctx, _, form, match} = 60 | #data{test, a, b} -> 61 | #if{test, a, b} 62 | #data{test, #multi! #multi{*match}} -> 63 | {`then{^a}`} -> 64 | #if{test, a, #value{undefined}} 65 | {`then{^a}`, `else{^b}`} -> 66 | #if{test, a, b} 67 | body -> 68 | match ctx: 69 | #expr{.multi} -> 70 | flatmacro{if_pattern} with 71 | {#seq{#multiple{*elifs}, #multiple{*elses}}} -> 72 | var rval = #value{undefined} 73 | elses each `else{^body}` -> 74 | rval = body 75 | elifs.reverse{} each `elif{^cond, ^body}` -> 76 | rval = #if{cond, body, rval} 77 | #if{test, #multi{*body}, rval} 78 | else -> 79 | #if{test, #multi{*body}, #value{undefined}} 80 | 81 | mac{"else"}! else_mac{match, _, form, _} = 82 | #pattern -> 83 | #ignore{} 84 | else -> 85 | throw E.syntax.else{msg, {node = form}} where 86 | msg = "'else' should be found inside an 'if' block" 87 | 88 | mac{"not"}! not_mac{match, _, form, #data{#void{}, rhs} and arg} = 89 | #check or #project -> 90 | #nostep{form} 91 | #pattern -> 92 | #neg{rhs} 93 | other -> 94 | #send{#variable{"not"}, arg} 95 | 96 | mac{"and"}! and_mac{match, _, form, #data{lhs, rhs} and arg} = 97 | #check or #project -> 98 | #nostep{form} 99 | #pattern -> 100 | #all{lhs, rhs} 101 | other -> 102 | #send{#variable{"and"}, arg} 103 | 104 | mac{"or"}! or_mac{match, _, form, #data{lhs, rhs} and arg} = 105 | #check or #project -> 106 | #nostep{form} 107 | #pattern -> 108 | #any{lhs, rhs} 109 | other -> 110 | #send{#variable{"or"}, arg} 111 | 112 | mac{"when"}! when_mac{context, _, form, #data{match, condition}} = 113 | #void{} -> #test{condition, #ignore{}} 114 | other -> #test{condition, other} 115 | 116 | mac{"?"}! check_mac{match context, info, form, #data{chk, target}} = 117 | do: 118 | checker = match info.step{#check{context}, chk}: 119 | === chk -> `getChecker{^chk}` 120 | checker -> checker 121 | #pattern -> 122 | subp = if{target == #void, #ignore, target} 123 | match checker: 124 | #raw{checker} -> 125 | checker 126 | else -> 127 | #check{checker, subp} 128 | when target == #void -> 129 | checker 130 | other -> 131 | `[^checker]{^target}` 132 | 133 | mac{"!"}! project_mac{match context, info, form, #data{proj, target}} = 134 | do: 135 | projector = match info.step{#project{context}, proj}: 136 | === proj -> `getProjector{^proj}` 137 | projector -> projector 138 | #pattern -> 139 | subp = if{target == #void, #ignore, target} 140 | match projector: 141 | #raw{projector} -> 142 | projector 143 | #unconditional{projector} -> 144 | #project{projector, subp, true} 145 | else -> 146 | #project{projector, subp} 147 | when target == #void -> 148 | `{x} -> [^projector]{x}[1]` 149 | other -> 150 | `[^projector]{^target}[1]` 151 | -------------------------------------------------------------------------------- /src/macros/loop.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./helpers" -> 4 | expr_mac 5 | overridable 6 | build_loop 7 | match_error 8 | Body 9 | 10 | 11 | setup_label{label, env, body} = 12 | #bind{`break` & {env = env}, #macro{break_mac{label}} 13 | #bind{`continue` & {env = env}, #macro{continue_mac{label}} 14 | #js_label{#value{label}, body}}} 15 | 16 | break_mac{default_label} = overridable with 17 | {context, _, form, match expr} -> 18 | #void{} when default_label -> #js_break{#value{default_label}} 19 | #void{} -> #js_break{} 20 | #value{v} -> #js_break{expr} 21 | #symbol{v} -> #js_break{#value{v}} 22 | 23 | continue_mac{default_label} = overridable with 24 | {context, _, form, match expr} -> 25 | #void{} when default_label -> #js_continue{#value{default_label}} 26 | #void{} -> #js_continue{} 27 | #value{v} -> #js_continue{expr} 28 | #symbol{v} -> #js_continue{#value{v}} 29 | 30 | inject: mac 31 | 32 | [items{defns} each {k, v} -> mac{k}{v}] where defns = { 33 | "break" => break_mac{null} 34 | "continue" => continue_mac{null} 35 | } 36 | 37 | expr_mac! mac{"while"}! while_mac{info, form, match {=> env}} = 38 | `[. ^[#symbol{label}]]` or #value{label} -> 39 | #macro with {context, _, form, #data{test, body}} -> 40 | setup_label{label, env, #js_while{test, body}} 41 | #data{test, body} -> 42 | setup_label{info.gensym{}, env, #js_while{test, body}} 43 | 44 | mac{"for"}! for_mac{context, info, form, match expr} = 45 | do: setup_for{label, env, match, body} = 46 | #multi{a, b, c} -> 47 | #multi with 48 | a 49 | setup_label{label, env, #js_for{#multi{}, b, c, body}} 50 | `^a in ^b` -> 51 | #multi with 52 | #declare{a, #value{null}} ;; this is to show the symbol as resolved 53 | setup_label{label, env, #js_for_in{a, b, body}} 54 | `^a of ^b` -> 55 | #multi with 56 | #declare{a, #value{null}} ;; this is to show the symbol as resolved 57 | setup_label{label, env, #js_for_of{a, b, body}} 58 | `[. ^[#symbol{label}]]` or #value{label} -> 59 | #macro with {context, _, form, #data{spec, body}} -> 60 | setup_for{label, expr.env, spec, body} 61 | #data{spec, body} -> 62 | setup_for{info.gensym{}, form.env, spec, body} 63 | 64 | 65 | class EachHandler: 66 | 67 | constructor{@placeholder, @loopvar, @generator = false} = 68 | @wrapOrder = 2 69 | 70 | expand{info} = 71 | @placeholder 72 | 73 | wrap{expr, info, opt} = 74 | if @generator: 75 | `^[@placeholder] each* ^[@loopvar] -> ^expr` 76 | else: 77 | `^[@placeholder] each ^[@loopvar] -> ^expr` 78 | 79 | 80 | mac{"each"}! each_mac{match, info and {=> env}, form, var expr} = 81 | 82 | #pattern -> 83 | if [expr == #void{}]: 84 | expr = #data{#void{}, #void{}} 85 | #data{li, body} = expr 86 | #special{EachHandler{ph, lv}} where 87 | ph = if{li == #void{}, info.env.mark{#symbol{info.gensym{.xs}}}, li} 88 | lv = if{body == #void{}, info.env.mark{`match`}, body} 89 | 90 | do: 91 | #data{li, body} = expr 92 | Body! {*clauses} = body 93 | var ends_with_test = false 94 | _build_loop{wrap, pre, post} = 95 | build_loop{info, env, form, li, clauses 96 | wrap, pre, post, opts} where opts = { 97 | 98 | forof = true 99 | wrap_pattern{x, toplevel} = 100 | set-var ends_with_test = 101 | match x: 102 | #test -> toplevel 103 | other -> false 104 | x 105 | fallback{target} = 106 | if ends_with_test: 107 | then: `false` 108 | else: match_error{target} 109 | } 110 | 111 | #test -> 112 | #test_factory{li, clauses} & {env = env} 113 | 114 | #expr{.multi} -> 115 | ;; expand{#multi} will call this macro again with either 116 | ;; #expr{.ignore} or #expr{.expr}, depending on whether we 117 | ;; are in the middle of a block or at the end of one. We want 118 | ;; to specialize on that information, so we pass our turn. 119 | #nostep{form} 120 | 121 | #expr{.ignore} -> 122 | ;; Middle of a block. This means we don't have to accumulate 123 | ;; the values. 124 | _build_loop{null, #splice{}, #splice{}} 125 | 126 | other -> 127 | ;; Middle of a block. We have to accumulate the values in 128 | ;; order to return them. Right now, this plays poorly with 129 | ;; break and continue. 130 | 131 | ;; _build_loop{{x} -> 'acc.push{^ #multi{x}}, '[var acc = {}], 'acc} 132 | _build_loop{{x} -> `temp = ^ #multi{x}, acc.push{temp}` 133 | #splice{`var acc = {}`, `var temp = null`} 134 | `acc`} 135 | 136 | 137 | mac{"each*"}! each_gen_mac{match, info and {=> env}, form, var expr} = 138 | 139 | #pattern -> 140 | if [expr == #void{}]: 141 | expr = #data{#void{}, #void{}} 142 | #data{li, body} = expr 143 | #special{EachHandler{ph, lv, true}} where 144 | ph = if{li == #void{}, info.env.mark{#symbol{info.gensym{.xs}}}, li} 145 | lv = if{body == #void{}, info.env.mark{`match`}, body} 146 | 147 | do: 148 | #data{li, body} = expr 149 | Body! {*clauses} = body 150 | var ends_with_test = false 151 | _build_loop{wrap, pre, post} = 152 | build_loop{info, env, form, li, clauses 153 | wrap, pre, post, opts} where opts = { 154 | 155 | forof = true 156 | wrap_pattern{x, toplevel} = 157 | set-var ends_with_test = 158 | match x: 159 | #test -> toplevel 160 | other -> false 161 | x 162 | fallback{target} = 163 | if ends_with_test: 164 | then: `false` 165 | else: match_error{target} 166 | } 167 | 168 | #expr{.multi} -> 169 | ;; expand{#multi} will call this macro again with either 170 | ;; #expr{.ignore} or #expr{.expr}, depending on whether we 171 | ;; are in the middle of a block or at the end of one. We want 172 | ;; to specialize on that information, so we pass our turn. 173 | #nostep{form} 174 | 175 | #expr{.ignore} -> 176 | ;; A generator in the middle of a block is a no-op. 177 | #multi{} 178 | 179 | other -> 180 | ;; Middle of a block. We create a generator and yield the 181 | ;; values. 182 | `[{} *-> ^loop]{}` where loop = 183 | _build_loop{{x} -> `temp = ^ #multi{x}, yield temp` 184 | #splice{`var acc = {}`, `var temp = null`} 185 | `acc`} 186 | -------------------------------------------------------------------------------- /src/macros/macrodef.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "../location" -> 4 | <<: 5 | "../expand" -> 6 | Env, topscope 7 | "./helpers" -> 8 | ctx_mac, expr_mac2, multimacro, inject-tools 9 | "../util" -> camelCase 10 | 11 | inject: mac 12 | 13 | ;;;;;;;;;;;; 14 | ;; MACROS ;; 15 | ;;;;;;;;;;;; 16 | 17 | wrap_macro{info, mac} = 18 | mac2{c, s, f, e} = 19 | bindings = info.env.list_bindings{info.scope} 20 | env = Env{} 21 | env.scopes[topscope.name] = bindings 22 | r = mac.call{info, c, s, f, e} 23 | env.mark{r} 24 | #macro{mac2} 25 | 26 | wrap_macro_func{info, args, body} = 27 | it = info.env.mark{`@`} 28 | `_lambda{^args, ^it = this, ^body, ^=null}` 29 | 30 | 31 | mac{"inlineMacro"}! imacro_mac{context, info, form, match} = 32 | #data{#send{name and [#symbol{sym} or #value{sym}], arguments}, ast} -> 33 | let mac = info.go{wrap_macro_func{info, arguments, ast}, .parse, .eval} 34 | s = info.mark{#symbol{sym} &: {env = name.env}} <<: name 35 | #declare_raw{s, wrap_macro{info, expr_mac2{mac}}} 36 | 37 | mac{"inlineCmacro"}! icmacro_mac{context, info, form, match} = 38 | #data{#send{name and [#symbol{sym} or #value{sym}], arguments}, ast} -> 39 | let mac = info.go{wrap_macro_func{info, arguments, ast}, .parse, .eval} 40 | s = info.mark{#symbol{sym} &: {env = name.env}} <<: name 41 | #declare_raw{s, wrap_macro{info, ctx_mac{mac}}} 42 | 43 | mac{"macros"}! macros_mac{context, info, form and {=> env}, #data{body}} = 44 | the_macros = info.go{body, .parse, .eval} 45 | #splice{*macs} where macs = 46 | items{the_macros} each {k, v} -> 47 | #declare_raw{#symbol{k} &: {env = env}, #macro{f}} where 48 | f{ctx, info, form, expr} = 49 | v.call{inject-tools{info}, expr} 50 | 51 | 52 | mac{"macro"}! macro_mac = mak{{}} where 53 | mak{tosave}{match, info, form, expr} = 54 | when expr == #void{} -> 55 | #nostep{form} 56 | #pattern -> 57 | #project{#macro{mac}, expr, true} where mac{*blah, #data{match}} = 58 | #use{env, x} -> 59 | #use{env, mac.call{this, #data{x}}} 60 | `^args -> ^body` -> 61 | e = wrap_macro_func{info, args, body} 62 | #multi{`tmp = ^e` 63 | `tmp.__deps and deps = {=}` 64 | *provides 65 | `tmp.__path = __filename` 66 | `tmp`} where 67 | provides = tosave each sym and #symbol{camelCase! name} -> 68 | `provide{^sym as ^exp}, deps[^=name] = ^=expn` where 69 | expn = "__mdep_" + name 70 | exp = #symbol{expn} 71 | match is expr -> 72 | #data{*tosave} -> 73 | #macro with mak{tosave} 74 | -------------------------------------------------------------------------------- /src/macros/modularity.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./helpers" -> 4 | Body, inject-tools 5 | "../location" -> [<<:] 6 | "../util" -> camelCase 7 | 8 | inject: mac 9 | 10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 11 | ;; REQUIRE/PROVIDE AND GLOBALS ;; 12 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | 14 | mac{"__require"}! __require_mac{context, info, form, expr} = 15 | req = #variable{.require} &: {top = true} 16 | `[^req][^expr]` 17 | 18 | mac{"__require-m"}! __requirem_mac{context, info, form, expr} = 19 | req = #variable{.require} &: {top = true} 20 | `[^req][^expr]` 21 | 22 | 23 | getreqs{info, req, expr, prefix = null} = 24 | 25 | stmts = {} 26 | names = {} 27 | var curpkg = null 28 | pkgs = {=} 29 | 30 | w{var x, args = null, wrap = null} = 31 | if args: 32 | x = `[^x][^args]` 33 | if wrap: 34 | x = wrap{x} 35 | x 36 | 37 | logName{name and [#symbol{camelCase! n} 38 | \ or #variable{n} 39 | \ or #value{"'" and n}]} = 40 | names.push with name 41 | pkgs[n] = curpkg 42 | if prefix === null: 43 | name 44 | else: 45 | res = match name: 46 | #symbol{s} -> #symbol{prefix + s} <<: name 47 | #variable{s} -> #symbol{prefix + s} <<: name 48 | #value{s} -> #symbol{prefix + s} <<: name 49 | res.other = name 50 | res 51 | 52 | unlogName{name} = 53 | match names.index-of{name.other or name}: 54 | === -1 -> pass 55 | n -> names.splice{n, 1} 56 | 57 | topfetch{pkg, v, args = null, wrap = null} = 58 | curpkg = pkg 59 | imp = w{`[^req]{^pkg}`, args, wrap} 60 | stmts.push with `let ^v = ^imp` 61 | v 62 | 63 | produce{match expr, fetch} = 64 | 65 | #symbol{s} -> 66 | fetch{#value{s}, logName{expr}} 67 | 68 | #value{String? s} -> 69 | fetch{expr, #symbol{info.gensym{}} &: {reqname = s}} 70 | 71 | #multi{*subp} or #data{*subp} -> 72 | subp each p -> produce{p, fetch} 73 | null 74 | 75 | #send{#symbol{"/"}, #data{#void{}, sym and #symbol{name}}} -> 76 | fetch{#value{'earlgrey-runtime/std/{name}'}, sym} 77 | 78 | #send{#symbol{"^"}, #data{#void{}, name}} -> 79 | fetch{name, #symbol{info.gensym{}} &: {reqname = name}} 80 | 81 | #send{#symbol{"as"}, #data{pkg, s}} -> 82 | produce{pkg} with {the_pkg, ignore, args = null, wrap = null} -> 83 | unlogName{ignore} 84 | fetch{the_pkg, logName{s}, args, wrap} 85 | 86 | #send{#symbol{"->"}, #data{pkg, subp}} -> 87 | pkgv = produce{pkg, fetch} 88 | rqn = pkgv.reqname or pkgv[1] 89 | produce{subp} with {_pkg, v, args = null, wrap = null} -> 90 | let pkg = match _pkg: 91 | #value{camelCase! s} -> #value{s} 92 | x -> x 93 | imp = w{`getProperty{^pkgv, ^pkg, ^=rqn}`, args, wrap} 94 | stmts.push{`let ^v = ^imp`} 95 | v 96 | 97 | #send{#symbol{match operator}, args} when expr.fromop -> 98 | "!" -> 99 | #data{projector, subp} = args 100 | produce{subp} with {the_pkg, name, args = null, var wrap = null} -> 101 | wrap or= [x -> x] 102 | fetch{the_pkg, name, args, wrap2} where wrap2{x} = 103 | `[^projector]{^wrap{x}}` 104 | else -> 105 | s = match info.raw{expr}.trim{}.replace{R"^,+|,+$", ""}: 106 | R"^\.*/"? x -> x 107 | R"^(\.+)(.*)"! {_, match pfx, rest} -> 108 | "." -> 109 | '{pfx}/{rest}' 110 | else -> 111 | '{dotdots.join{""}}{rest}' where 112 | dotdots = 2..pfx.length each _ -> "../" 113 | text -> 114 | text 115 | name = match s.split{"/"}: 116 | {*, R"^[a-zA-Z0-9_\-]+$"? name} -> name 117 | {*, other} -> 118 | throw E.syntax.module{ 119 | '`{other}` is not a valid symbol; use `require: "{s}" as xyz` instead' 120 | {node = expr} 121 | } 122 | sym = info.mark{#symbol{name}} 123 | fetch{#value{s}, logName{sym}} 124 | 125 | #send{name and #symbol{s}, args and #data{*_}} -> 126 | fetch{#value{s}, logName{name}, args} 127 | 128 | produce{expr, topfetch} 129 | {stmts, names, pkgs} 130 | 131 | 132 | 133 | mac{"require"}! require_mac{context, info, form, match arg} = 134 | do: req = info.mark{`__require`} 135 | 136 | #void{} -> 137 | #variable{.require} 138 | 139 | #value{field} -> 140 | #send{req, arg} 141 | 142 | #data{expr} or expr is arg -> 143 | {stmts, _, _} = getreqs{info, req, expr} 144 | #splice{*stmts} 145 | 146 | 147 | mac{"requireMacros"}! requiremac_mac{context, info, form, match arg} = 148 | #data{expr} or expr is arg -> 149 | req = info.mark{`__require-m`} 150 | {stmts, vars, pkgs} = getreqs{info, req, expr, "$MAC$"} 151 | body = 152 | #multi{*stmts, #data{*vs}} where 153 | vs = vars each v and [#symbol{s} or #variable{s} or #value{s}] -> 154 | `^v = ^[#symbol{"$MAC$" + s}]` 155 | body <<: arg 156 | the_macros = info.go{body, .parse, .eval} 157 | user-req = info.mark{`require`} 158 | declarations = #splice{*macs} where macs = 159 | items{the_macros} each {k, {"macro" => v} or v} when Function? v -> 160 | var r = #splice{} 161 | deps = if{v.__deps, clone{v.__deps}, {=}} 162 | r ++= 163 | items{v.__deps or {=}} each {name, ename} -> 164 | ;; TODO: setting the global seems to make the REPL work, but 165 | ;; it would be better not to do that... 166 | mangled-name = info.gensym{"_mdep_" + name} 167 | mangled = #variable{mangled-name} 168 | deps[name] = mangled 169 | #splice with 170 | `[^user-req]: ^[pkgs[k]] -> ^[#symbol{ename}] as ^mangled` 171 | \ &: {env = info.env} 172 | `global[^=mangled-name] = ^mangled` 173 | f{ctx, info, form, expr} = 174 | info.deps = deps 175 | v.call{inject-tools{info}, expr} 176 | r.push with 177 | #declare_raw{#symbol{k} &: {env = info.env}, #macro{f}} 178 | r 179 | 180 | #restmacro with {stmts} -> 181 | {declarations, #multi{*stmts}} 182 | 183 | mac{"provide"}! provide_mac{match context, _, form, e} = 184 | #pattern -> 185 | match e: 186 | #void{} -> `module.exports and set-var ^[#variable{.exports}]` 187 | else -> `(module.exports and set-var ^[#variable{.exports}])[^e]` 188 | else -> 189 | #data{Body! {*expr}} = e 190 | exp = form.env.mark{`exports`} 191 | #sink with 192 | #multi ++ 193 | expr each 194 | s and #symbol{name} -> 195 | `[^exp][^=camelCase{name}] = ^s` 196 | `^s as ^[#symbol{name} or #value{name}]` -> 197 | `[^exp][^=camelCase{name}] = ^s` 198 | other -> 199 | throw E.syntax.provide with 200 | "Each clause of provide must be 'sym' or 'sym as name'" 201 | 202 | mac{"inject"}! inject_mac{context, _, form, #data{Body! {*expr}}} = 203 | #restmacro with {stmts} -> 204 | exp = form.env.mark{`exports`} 205 | {``` 206 | globals: module 207 | module.exports{^*expr} = 208 | var ^exp = {=} 209 | ^[#multi{*stmts}] 210 | ^exp 211 | ```} 212 | 213 | mac{"globals"}! globals_mac{context, _, form, #data{Body! {*vars}}} = 214 | #splice{*globs, `undefined`} where globs = 215 | vars each variable and #symbol{s} -> 216 | #splice{ 217 | #declare_raw{variable, #variable{camelCase{s}} &: {top = true, mutable = true}} 218 | `if typeof{^variable} === "undefined": global[^=s] = undefined` 219 | } 220 | -------------------------------------------------------------------------------- /src/macros/operators.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./helpers" -> 4 | partial_pattern 5 | make_assigner 6 | overridable 7 | 8 | inject: mac 9 | 10 | [items{defns} each {k, v} -> mac{k}{v}] where defns = { 11 | 12 | "===" => partial_pattern{"==="} 13 | "!==" => partial_pattern{"!=="} 14 | "in" => partial_pattern{"__in__"} 15 | "==" => partial_pattern{"equal"} 16 | "!=" => partial_pattern{"nequal"} 17 | "<=" => partial_pattern{"<="} 18 | ">=" => partial_pattern{">="} 19 | "<" => partial_pattern{"<"} 20 | ">" => partial_pattern{">"} 21 | 22 | "+=" => make_assigner{"+"} 23 | "-=" => make_assigner{"-"} 24 | "*=" => make_assigner{"*"} 25 | "/=" => make_assigner{"/"} 26 | "<<=" => make_assigner{"<<"} 27 | ">>=" => make_assigner{">>"} 28 | ">>>=" => make_assigner{">>>"} 29 | "++=" => make_assigner{"++"} 30 | "?=" => make_assigner{"match"} 31 | "or=" => make_assigner{"or"} 32 | "and=" => make_assigner{"and"} 33 | "each=" => make_assigner{"each"} 34 | 35 | } 36 | 37 | mac{"is"}! is_mac{match, _, form, #data{x, y}} = 38 | #pattern -> 39 | #replace{x, y} 40 | else -> 41 | `^x === ^y` 42 | 43 | overridable! mac{"-"}! minus_mac{context, _, form, match expr} = 44 | #data{#void{}, #value{Number? n}} -> 45 | #value{-n} 46 | #void{} -> 47 | #variable{"-"} 48 | other -> 49 | #send{#variable{"-"}, expr} 50 | 51 | overridable! mac{"++"}! append_mac{context, _, form, match} = 52 | #data{#void{}, x} -> #send{#variable{"++"}, #data{#void{}, x}} 53 | #data{x, #void{}} -> #send{#variable{"++"}, #data{x, #void{}}} 54 | #data{x, y} -> `[^x].concat{^y}` 55 | #void{} -> `{x, y} -> x.concat{y}` 56 | other -> `___build_array{^other}` 57 | 58 | overridable! mac{".."}! range_mac{context, _, form, match} = 59 | #data{#void{}, x} -> `range{1, ^x}` 60 | #data{x, #void{}} -> `range{^x}` 61 | #data{x, y} -> `range{^x, ^y}` 62 | #void{} -> `range` 63 | 64 | overridable! mac{"..."}! xrange_mac{context, _, form, match} = 65 | #data{#void{}, x} -> `range{0, ^x - 1}` 66 | #data{x, #void{}} -> `range{^x}` 67 | #data{x, y} -> `range{^x, ^y - 1}` 68 | 69 | overridable! mac{"//"}! floor_mac{context, _, form, match} = 70 | #void{} -> 71 | `{a, b} -> Math.floor{a / b}` 72 | #data{a, b} -> 73 | `Math.floor{^a / ^b}` 74 | 75 | mac{"*"}! times_mac{context, _, form, expr} = 76 | match {context, expr}: 77 | {#pattern, #void{}} -> 78 | #dynsplice{#ignore{}} 79 | {#pattern or #expr{.data}, #data{#void{}, val}} -> 80 | #dynsplice{val} 81 | {_, #void{}} -> 82 | #variable{"*"} 83 | other -> 84 | #send{#variable{"*"}, expr} 85 | 86 | overridable! mac{"**"}! exp_mac{context, _, form, expr} = 87 | match {context, expr}: 88 | {#pattern, #void{}} -> 89 | #objsplice{#ignore{}} 90 | {#pattern or #expr{.data}, #data{#void{}, val}} -> 91 | #objsplice{val} 92 | {_, #void{}} -> 93 | `Math.pow` 94 | {_, #data{a, b}} -> 95 | `Math.pow{^a, ^b}` 96 | 97 | mac{">>"}! shift_mac{match, _, form, expr} = 98 | #pattern -> 99 | #data{variable, result} = expr 100 | #project{`{^variable} -> {true, ^result}`, variable} 101 | else -> 102 | #send{#variable{">>"}, expr} 103 | -------------------------------------------------------------------------------- /src/macros/quote.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "../lex" -> unescape 4 | "../location" -> Source 5 | "./helpers" -> 6 | qq, overridable 7 | opg 8 | ;; quaint 9 | 10 | inject: mac 11 | 12 | ;;;;;;;;;;;;; 13 | ;; UNQUOTE ;; 14 | ;;;;;;;;;;;;; 15 | 16 | mac{"^"}! unquote_mac{match context, info, form, expr} = 17 | #expr{.head} -> 18 | #nostep{} 19 | #pattern -> 20 | #data{#void{}, x} = expr 21 | #calc{x} 22 | else -> 23 | throw E.syntax.unquote{'Cannot unquote in context {context}.', expr = expr} 24 | 25 | 26 | ;;;;;;;;;;; 27 | ;; QUOTE ;; 28 | ;;;;;;;;;;; 29 | 30 | mac{"`"}! quote_mac{match context, info, form, expr and #value{s}} = 31 | do: 32 | parsed = info.go{Source{s, ""}, .source, .parse} 33 | ;; #expr -> 34 | ;; info.mark{`^qq{parsed, true} &: {ast = true}`} 35 | else -> 36 | info.mark{qq{parsed}} 37 | 38 | 39 | ;;;;;;;;;;;;;;;;; 40 | ;; INTERPOLATE ;; 41 | ;;;;;;;;;;;;;;;;; 42 | 43 | tok = opg.tokenize.Tokenizer with { 44 | regexps = { 45 | ;; open = "\\$[.A-Za-z0-9_]*\\{|\\{" 46 | ;; close = "\\}" 47 | ;; other = "\\$|[^\\{\\}$]+" 48 | open = "\\{" 49 | close = "\\}" 50 | other = "(?:\\\\.|[^\\{\\}])+" 51 | } 52 | post = { 53 | {match tok} -> 54 | {type => .open} -> 55 | ;; Insert a dummy token before { 56 | ;; The dummy token serves as a kind of wedge between } and { in '{x}{y}' 57 | ;; Without that token, {y} will be the right hand side of {x} and that's 58 | ;; a pain to deal with. 59 | {{token = "", type = .other, location = tok.location.at_start{}}, tok} 60 | else -> 61 | tok 62 | } 63 | } 64 | 65 | gr = new opg.parse.TokenGroups with { 66 | open = {"open"} 67 | close = {"close"} 68 | other = {"str", "other"} 69 | } 70 | 71 | prio = new opg.parse.PriorityOrder{gr} with { 72 | open = {left = 1002, right = 0} 73 | close = {left = 0, right = 1003} 74 | other = {left = 1000, right = 1000} 75 | } 76 | 77 | finalize{match zazz} = 78 | {null? 79 | {type => "open", token => [match open]} 80 | _arg 81 | {type => "close", token => close} 82 | null?} -> 83 | do: 84 | let arg = _arg or #join{""} & {text = ""} 85 | let text = open + arg.text + close 86 | R"\$([^\{]*){"! {_, tag} or tag is "" -> 87 | #bracket{tag, arg.text} &: {text = text} 88 | {null?, {=> token}, null?} -> 89 | #join{token} &: {text = token} 90 | args -> 91 | var rval = #join{} 92 | var text = "" 93 | enumerate{args} each {i, match arg} -> 94 | {=> token} when i mod 2 == 1 -> 95 | rval.push{token} 96 | text += token 97 | #join{*sub} -> 98 | text += arg.text 99 | rval ++= sub 100 | #bracket -> 101 | text += arg.text 102 | rval.push{arg} 103 | null? -> 104 | pass 105 | rval &: {text = text} 106 | 107 | parser = new opg.parse.Parser{tok, prio.getOrder{}, finalize} 108 | 109 | parse{text} = 110 | parser.parse{text} 111 | 112 | 113 | overridable! mac{"wrap-quote"}! wq_mac{context, info, form, `{^x}`} = 114 | match x: 115 | `ENode{{}, {=}, {^*elements}}` and match is elements -> 116 | {v and #value{String?}} -> v 117 | {#value{String?}, *} -> 118 | elements.reduce{f,} where f{x, y} = `^x + ^y` 119 | else -> 120 | elements.reduce{f, `""`} where f{x, y} = `^x + ^y` 121 | else -> 122 | `[^x].to-string{}` 123 | 124 | mac{"'"}! interpolate_mac{context, info, form, #value{s}} = 125 | #join{*contents} or contents is {} = parse{s} 126 | parts = {} 127 | var current = "" 128 | push{} = 129 | if current != "": 130 | parts.push{#value{current}} 131 | current = "" 132 | contents each 133 | String? s -> 134 | current += unescape{s} 135 | #bracket{match, expr} -> 136 | do: 137 | push{} 138 | p = form.env.mark{#parse{expr}} 139 | "" -> 140 | parts.push with p 141 | ;; "" -> 142 | ;; parts.push with `ENode{{}, {=}, {^p}}` 143 | ;; tag -> 144 | ;; parts.push with `ENode{{^=tag}, {=}, {^p}}` 145 | push{} 146 | 147 | wq = form.env.mark{`wrap-quote`} 148 | `[^wq]{ENode{{}, {=}, {^*parts}}}` 149 | 150 | -------------------------------------------------------------------------------- /src/macros/regexp.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "../location" -> Source 4 | "./helpers" -> accum_flags 5 | 6 | inject: mac 7 | 8 | ;;;;;;;;;;;;;;;;;;;;;;;;; 9 | ;; REGULAR EXPRESSIONS ;; 10 | ;;;;;;;;;;;;;;;;;;;;;;;;; 11 | 12 | class RegexBuilder: 13 | 14 | wrap{x} = 15 | "(?:" + x + ")" 16 | 17 | quote{x} = 18 | x.replace{R.g`{in ".?*+^$[](){}|\\\\"}`, "\\$1"} 19 | 20 | quote_charset{x} = 21 | x.replace{R.g`{in "[](){}^"}`, "\\$1"} 22 | 23 | build{expr} = 24 | match expr: 25 | #symbol{match} -> 26 | .any -> "." 27 | .start -> "^" 28 | .end -> "$" 29 | .alpha -> "\\a" 30 | .digit -> "\\d" 31 | .word -> "\\w" 32 | .space -> "\\s" 33 | .boundary -> "\\b" 34 | .a -> "\\a" 35 | .d -> "\\d" 36 | .w -> "\\w" 37 | .s -> "\\s" 38 | .b -> "\\b" 39 | 40 | #value{x} -> @quote{x} 41 | 42 | #send{#symbol{"raw"}, #value{s}} -> 43 | s 44 | 45 | #send{#symbol{match}, #data{a, b}} -> 46 | "||" -> 47 | @wrap{@build{a} + "|" + @build{b}} 48 | "or" -> 49 | @wrap{@build{a} + "|" + @build{b}} 50 | "*" -> 51 | #void{} = a 52 | @wrap{@build{b} + "*"} 53 | "+" -> 54 | #void{} = a 55 | @wrap{@build{b} + "+"} 56 | "?" -> 57 | #void{} = a 58 | @wrap{@build{b} + "?"} 59 | "in" -> 60 | #void{} = a 61 | #value{v} = b 62 | ["[" + x + "]"] where 63 | x = @quote_charset{v} 64 | "not" -> 65 | #void{} = a 66 | #send{#symbol{"in"}, #data{#void{}, #value{v}}} = b 67 | ["[^" + x + "]"] where 68 | x = @quote_charset{v} 69 | 70 | #data{*args} -> 71 | "(" + [args each arg -> @build{arg}].join{""} + ")" 72 | #multi{*args} -> 73 | "(?:" + [args each arg -> @build{arg}].join{""} + ")" 74 | 75 | other -> 76 | E.syntax.regexp with 77 | "Illegal regular expression" 78 | {expr = expr} 79 | 80 | build_regexp{x} = RegexBuilder{}.build{x} 81 | 82 | accum_flagsf{f} = accum_flags{f, false} 83 | accum_flagsf! mac{"R"}! regexp_mac{match, info, form, var arg, flags} = 84 | #check or #project -> 85 | #nostep{form} 86 | else -> 87 | match arg: 88 | #value{String? v} -> 89 | text = 90 | ;; match arg.location.text{}: 91 | match info.gettext{arg}: 92 | R"^\".*\"$"? text -> text.substring{1, text.length - 1} 93 | text -> text 94 | `RegExp{^=text, ^=[flags.join{""}]}` 95 | #send{#symbol{"'"}, #data{#void{}, arg}} -> 96 | `RegExp{^=build_regexp{arg}, ^=[flags.join{""}]}` 97 | #send{#symbol{"`"}, #value{s}} -> 98 | arg = info.go{Source{s, ""}, .source, .parse} 99 | `RegExp{^=build_regexp{arg}, ^=[flags.join{""}]}` 100 | -------------------------------------------------------------------------------- /src/opt.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./location" -> 4 | <<: 5 | 6 | provide: 7 | hoist 8 | eliminate_spurious_variables 9 | 10 | 11 | s{stats, v} = 12 | if [not Object.hasOwnProperty.call{stats, v}]: 13 | stats[v] = { 14 | assigns = 0 15 | uses = 0 16 | transfers = {} 17 | replaceable = false 18 | } 19 | stats[v] 20 | 21 | varstats{match expr, stats} = 22 | #assign{#variable{v1}, #variable{v2}} -> 23 | s{stats, v1}.assigns += 1 24 | s{stats, v2}.uses += 1 25 | s{stats, v2}.transfers.push{v1} 26 | #assign{#variable{v1}, expr} -> 27 | s{stats, v1}.assigns += 1 28 | varstats{expr, stats} 29 | #variable{v} -> 30 | s{stats, v}.uses += 1 31 | #value -> 32 | pass 33 | #scope{vars, body} -> 34 | vars each #variable{v} -> 35 | s{stats, v}.replaceable = true 36 | varstats{body, stats} 37 | #lambda{vars, body, generator = null} -> 38 | vars each #variable{v} -> 39 | s{stats, v}.assigns += 1 40 | varstats{body, stats} 41 | other -> 42 | other.slice{1} each x -> 43 | varstats{x, stats} 44 | 45 | replaceVars{match expr, repl} = 46 | #variable{v} when Object.hasOwnProperty.call{repl, v} and repl[v] -> 47 | #variable{repl[v]} <<: expr 48 | #assign{#variable{v1}, #variable{v2}} when repl[v1] == v2 or repl[v2] == v1 -> 49 | #multi{} <<: expr 50 | #variable or #value -> 51 | expr 52 | #scope{vars, body} -> 53 | newvars = {} 54 | vars each _var and #variable{v} -> 55 | if Object.hasOwnProperty.call{repl, v}: 56 | if repl[v] !== false: 57 | newvars.push with 58 | #variable{repl[v]} <<: _var 59 | else: 60 | newvars.push{_var} 61 | #scope{ 62 | newvars 63 | replaceVars{body, repl} 64 | } <<: expr 65 | #lambda{vars, body, generator = null} -> 66 | #lambda{ 67 | vars 68 | replaceVars{body, repl} 69 | generator 70 | } <<: expr 71 | {x, *rest} -> 72 | [{x, *newrest} <<: expr] where newrest = 73 | rest each elem -> 74 | replaceVars{elem, repl} 75 | other -> 76 | console.error{other} 77 | throw E.replaceVars{"Unknown: " + String{other}} 78 | 79 | ;; decl x 80 | ;; x = f{y} 81 | ;; decl z 82 | ;; z = x 83 | ;; bab{z, z, z} 84 | ;; ===> 85 | ;; decl z 86 | ;; z = f{y} 87 | ;; bab{z, z, z} 88 | 89 | ;; repl[x] = z 90 | ;; repl[z] = _ 91 | 92 | eliminate_spurious_variables{expr} = 93 | stats = {=} 94 | varstats{expr, stats} 95 | repl = {=} 96 | items{stats} each {v, st} -> 97 | if st.uses == 1 and st.assigns == 1 and st.transfers.length == 1 and st.replaceable: 98 | {tr} = st.transfers 99 | st2 = s{stats, tr} 100 | if st2.assigns == 1 and st2.replaceable: 101 | repl[v] = tr 102 | repl[tr] = false 103 | st.replaceable = false 104 | st2.replaceable = false 105 | replaceVars{expr, repl} 106 | 107 | 108 | 109 | hoist{expr} = 110 | {b, inner} = hoist_helper{expr} 111 | #scope{inner, b} 112 | 113 | ;; Nodes over which variable declarations can be hoisted. For 114 | ;; instance, #if{#multi{#deciare{x}, x}, ...} can be changed 115 | ;; into #multi{#declare{x}, #if{x, ...}} 116 | ;; This group also (implicitly) contains #scope. 117 | 118 | hoistable = { 119 | .send, .array, .object, .multi 120 | .if, .assign 121 | .js_break, .js_continue, .js_return 122 | .js_delete, .js_throw, .js_try, .js_new 123 | .js_yield 124 | } 125 | 126 | ;; Nodes over which we will *not* hoist declarations. For instance, 127 | ;; declarations inside a for loop will remain there. This group also 128 | ;; (implicitly) contains #lambda. 129 | 130 | not_hoistable = { 131 | .void 132 | .js_while, .js_for, .js_for_in, .js_for_of, .js_label, .js_class 133 | } 134 | 135 | hoist_helper{match expr} = 136 | 137 | ;; This floats variable declarations to the top as much as 138 | ;; possible. It is assumed that we alpha renamed all variables 139 | ;; beforehand, so there is no risk of name collision. The purpose 140 | ;; of this phase is to avoid wrapping scopes in (function(){...}()) 141 | ;; when generating code. 142 | 143 | ;; Variables are declared either as 144 | ;; #scope{vars, body} (no closure) 145 | ;; or as 146 | ;; #lambda{vars, body} (closure) 147 | 148 | ;; The return value of hoist_helper is 149 | ;; {new_expression, hoisted_variables} 150 | 151 | #symbol or #value or #variable -> 152 | ;; No variables here. 153 | {expr, {}} 154 | 155 | #scope{vars, body} -> 156 | ;; We simply merge the variables with the variables to hoist 157 | ;; from body. 158 | {newbody, inner} = hoist_helper{body} 159 | {newbody, inner ++ vars} 160 | 161 | #lambda{vars, body, generator} -> 162 | ;; Can't hoist past this! We create a #scope to hold the 163 | ;; variables hoisted from body. 164 | {newbody, inner} = hoist_helper{body} 165 | newlambda = #lambda{vars, #scope{inner, newbody} <<: body, generator} &: 166 | {name = expr.name} 167 | {newlambda <<: expr, {}} 168 | 169 | {type, *args} when hoistable.indexOf{type} !== -1 -> 170 | ;; Hoistable nodes. We assume that all the members of the node 171 | ;; are expressions, so we accumulate hoistable variables from 172 | ;; all of them. 173 | var accum = {} 174 | newargs = args each arg -> 175 | {b, inner} = hoist_helper{arg} 176 | accum ++= inner 177 | b 178 | {{type, *newargs} <<: expr, accum} 179 | 180 | {type, *args} when not_hoistable.indexOf{type} !== -1 -> 181 | ;; Not hoistable. We assume that all the members of the node are 182 | ;; expressions. We create #scopes for each argument, if needed. 183 | newargs = args each arg -> 184 | {b, inner} = hoist_helper{arg} 185 | match inner: 186 | {} -> b 187 | other -> 188 | #scope{inner, b} 189 | {{type, *newargs} <<: expr, {}} 190 | 191 | other -> 192 | ;; hoistable and not_hoistable should contain all possible node types 193 | throw E.syntax.illegal{"Illegal node -- this should not happen.", {node = other}} 194 | -------------------------------------------------------------------------------- /src/pp.eg: -------------------------------------------------------------------------------- 1 | 2 | 3 | provide: 4 | pr_terminus 5 | pr, <> 6 | repr 7 | 8 | 9 | 10 | 11 | 12 | 13 | pr_terminus{node} = 14 | r = HTML{node, .span} 15 | pre = String.fromCharCode{27} + "[?0;7y+h
" 16 | post = "
" + String.fromCharCode{7} 17 | console.log with [pre + r + post] 18 | 19 | pr{match, r} = 20 | ENode? n -> 21 | pr_terminus{n} 22 | x -> 23 | pr_terminus{[r or repr]{x}} 24 | 25 | [<> x] = pr{x} 26 | 27 | let repr{x and match, Function? recur = repr} = 28 | === true -> .special.true % "true" 29 | === false -> .special.false % "false" 30 | null? -> .special.nil % "null" 31 | undefined? -> .special.nil % "undefined" 32 | Number? -> .num % String{x} 33 | String? -> .str % x 34 | ;; Struct? {tag, *entries} -> 35 | ;; .struct % {.sym % tag, .sequence % [entries each x -> recur{x, repr}]} 36 | Array? entries -> 37 | .sequence % [entries each x -> recur{x, repr}] 38 | when x["::repr"] -> 39 | x["::repr"]{recur} 40 | when Object.getPrototypeOf{x} === Object.prototype -> 41 | table.object % 42 | items{x} each {k, v} -> 43 | tr % 44 | th % recur{k, repr} 45 | td % recur{v, repr} 46 | ;; when Object.getPrototypeOf{x} === Object.prototype -> 47 | ;; .table % 48 | ;; items{x} each {k, v} -> 49 | ;; .pairing % 50 | ;; recur{k, repr} 51 | ;; recur{v, repr} 52 | other -> 53 | .unknown % other.toString{} 54 | 55 | 56 | escape_html{String! s} = 57 | repl = with 58 | "&" => "&" 59 | "<" => "<" 60 | ">" => ">" 61 | s.replace{R.g"[&<>]", {x} -> repl[x]} 62 | 63 | quotify{String! s} = 64 | s.replace{R.g"[\"\\]", {x} -> "\\" + x} 65 | 66 | 67 | HTML{match, default_tag} = 68 | 69 | String? s -> 70 | escape_html{s} 71 | 72 | Array? children -> 73 | chs.join{""} where chs = 74 | children each child -> HTML{child, default_tag} 75 | 76 | ENode? {=> tags, => props, => children} -> 77 | var tag = default_tag or "span" 78 | classes = {} 79 | var id = null 80 | kv = {} 81 | sub = {} 82 | tags each 83 | R"^\.(.*)"! {_, cls} -> 84 | classes.push with cls 85 | other -> 86 | tag = other 87 | 88 | items{props} each {k, v} -> 89 | kv.push with {k, v} 90 | 91 | var accum = if{tag === .raw, {}, {"<", tag}} 92 | if id: 93 | set-var accum = accum.concat with 94 | " id=\"", id, "\"" 95 | if classes.length: 96 | set-var accum = accum.concat with 97 | " class=\"", quotify{classes.join{" "}}, "\"" 98 | if kv: 99 | kv each {k, v} -> 100 | set-var accum = accum.concat with 101 | if [v !== null]: 102 | then: {" ", k, "=\"", quotify{v}, "\""} 103 | else: {" ", k} 104 | 105 | children2 = match tag: 106 | .raw -> children each 107 | String? s -> s 108 | c -> HTML{c, default_tag} 109 | other -> children each c -> HTML{c, default_tag} 110 | 111 | match tag: 112 | .raw -> 113 | accum.concat{children2}.join{""} 114 | other -> 115 | accum.concat{x}.join{""} where x = 116 | {">", *children2, ""} 117 | 118 | 119 | ;; ENode? {=> classes, => children} -> 120 | ;; var tag = default_tag or "span" 121 | ;; _classes = {} 122 | ;; var id = null 123 | ;; kv = {} 124 | ;; sub = {} 125 | ;; classes each 126 | ;; #assoc{k, v} -> 127 | ;; kv.push with {k, v} 128 | ;; #assoc{k} -> 129 | ;; kv.push with {k, undefined} 130 | ;; R'[start, "+", {*any}]! {_, m} -> 131 | ;; set tag = m 132 | ;; R'[start, "#", {*any}]! {_, m} -> 133 | ;; set id = m 134 | ;; String? s -> 135 | ;; _classes.push with s 136 | 137 | ;; var accum = if{tag === .raw, {}, {"<", tag}} 138 | ;; if id: 139 | ;; set accum = accum.concat with 140 | ;; " id=\"", id, "\"" 141 | ;; if _classes.length: 142 | ;; set accum = accum.concat with 143 | ;; " class=\"", quotify{_classes.join{" "}}, "\"" 144 | ;; if kv: 145 | ;; kv each {k, v} -> 146 | ;; set accum = accum.concat with 147 | ;; if [v !== null]: 148 | ;; then: {" ", k, "=\"", quotify{v}, "\""} 149 | ;; else: {" ", k} 150 | 151 | ;; children2 = match tag: 152 | ;; .raw -> children each 153 | ;; String? s -> s 154 | ;; c -> HTML{c, default_tag} 155 | ;; other -> children each c -> HTML{c, default_tag} 156 | 157 | ;; match tag: 158 | ;; .raw -> 159 | ;; accum.concat{children2}.join{""} 160 | ;; other -> 161 | ;; accum.concat{x}.join{""} where x = 162 | ;; {">", *children2, ""} 163 | 164 | other -> 165 | HTML{String! other, default_tag} 166 | 167 | -------------------------------------------------------------------------------- /src/register.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | fs 4 | path 5 | "source-map-support" as sm 6 | "./version" -> version 7 | 8 | globals: 9 | module 10 | JSON 11 | 12 | provide: 13 | getCache 14 | install 15 | 16 | 17 | sm.install{} 18 | 19 | getCache{file, opts = {=}} = 20 | 21 | cachedir = path.join{path.dirname{file}, "egcache"} 22 | cache = path.join{cachedir, path.basename{file}.replace{R".eg$|$", ".js"}} 23 | cacheoptsFile = cache.replace{R".js$|$", ".json"} 24 | 25 | sstat = fs.statSync{file} 26 | cstat = fs.statSync{cache} !! e -> null 27 | cacheopts = JSON.parse{fs.readFileSync{cacheoptsFile, .utf8}} !! e -> null 28 | newcacheopts = { 29 | versions = { 30 | ecmascript = if{opts.es5, 5, 6} 31 | earlgrey = version 32 | } 33 | runtime = opts.runtime 34 | parameters = opts.parameters or {=} 35 | } 36 | 37 | {g, compiled, srcfile} = 38 | if not opts.recompile 39 | \ and not opts.interactive 40 | \ and cacheopts == newcacheopts 41 | \ and cstat and sstat.mtime.getTime{} < cstat.mtime.getTime{}: 42 | if opts.verbose: 43 | console.error{"Using cached file: " + cache} 44 | {null, fs.readFileSync{cache, .utf8}, cache} 45 | else: 46 | require: 47 | "./earl-grey" as eg 48 | "./location" -> 49 | Source 50 | if opts.verbose: 51 | console.error{"Compiling: " + file} 52 | text = fs.readFileSync{file, .utf8} 53 | let g = eg.Generator{{sourceMap = true} & opts} 54 | {=> code, => map} or code and map is null = 55 | g.generate{Source{text, file}} 56 | try: 57 | fs.mkdirSync{cachedir} !! e -> "ignore error" 58 | fs.writeFileSync{cache, code} 59 | fs.writeFileSync{cache + ".map", map} 60 | fs.writeFileSync{cacheoptsFile, JSON.stringify{newcacheopts}} 61 | catch e: 62 | console.error{"Failed to cache compiled version of: " + file} 63 | {g, code, cache} 64 | 65 | {g, compiled, srcfile} 66 | 67 | 68 | load{opts}{module, file} = 69 | {_, compiled, srcfile} = getCache{file, opts} 70 | module._compile{compiled, srcfile} 71 | 72 | 73 | extensions = {".eg"} 74 | 75 | install{opts = {recompile = false, runtime = null}} = 76 | req = require 77 | if [xreg = req.extensions]: 78 | extensions each ext -> 79 | if not xreg[ext]: 80 | xreg[ext] = load{opts} 81 | 82 | -------------------------------------------------------------------------------- /src/stdenv.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | "./expand" as mt -> 4 | Env, Expander, topscope 5 | 6 | 7 | provide: 8 | stdenv 9 | make_expander 10 | 11 | 12 | stdenv = Env{} 13 | 14 | mac{name}{m} = 15 | m2{ctx, info, form, match expr} = 16 | {brackets => "()"} -> 17 | throw E.syntax.no_parens with 18 | "Parentheses cannot be used here. 19 | Use [] or {} depending on your intent. 20 | []s are usually equivalent to an absence 21 | of brackets. 22 | ".replace{R.g"\n *", " "} 23 | {expr = expr} 24 | else -> 25 | m.call{this, ctx, info, form, expr} 26 | stdenv.bind{topscope, name, #macro{m2}} 27 | m2 28 | 29 | bind{name, value} = 30 | stdenv.bind{topscope, name, value} 31 | 32 | ;; "consts core operators loop quote regexp modularity 33 | ;; testing misc macrodef async logic".split{R"[\n ]+"} each 34 | ;; m -> require{^["./macros/" + m]}{mac, bind} 35 | 36 | require{"./macros/consts"}{mac, bind} 37 | require{"./macros/core"}{mac, bind} 38 | require{"./macros/operators"}{mac, bind} 39 | require{"./macros/loop"}{mac, bind} 40 | require{"./macros/quote"}{mac, bind} 41 | require{"./macros/regexp"}{mac, bind} 42 | require{"./macros/modularity"}{mac, bind} 43 | require{"./macros/misc"}{mac, bind} 44 | require{"./macros/macrodef"}{mac, bind} 45 | require{"./macros/async"}{mac, bind} 46 | require{"./macros/logic"}{mac, bind} 47 | 48 | 49 | make_expander{pipeline} = 50 | Expander{stdenv.fork{}, generic_nodes, pipeline} where 51 | generic_nodes = { 52 | .if 53 | .js_while, .js_for, .js_for_in, .js_for_of, .js_label 54 | .js_break, .js_continue, .js_return 55 | .js_delete, .js_throw, .js_try, .js_new 56 | .js_yield 57 | .js_class, .js_super 58 | } 59 | -------------------------------------------------------------------------------- /src/util.eg: -------------------------------------------------------------------------------- 1 | 2 | provide: 3 | GenSym, gensym 4 | identity 5 | binsearch 6 | classify, classify_contiguous 7 | ;; _neighbours 8 | partition 9 | construct 10 | mkset 11 | ;; product 12 | Body 13 | camelCase 14 | invCamelCase 15 | mac1, checker_db 16 | 17 | 18 | GenSym{prefix} = 19 | ;; Simple symbol generator. 20 | ;; g = GenSym{"$"} 21 | ;; g{} ==> "$0", "$1", "$2", ... 22 | ;; g{"xyz"} ==> "xyz$0", "xyz$1", "xyz$2", ... 23 | id = 0 24 | {pfx = ""} -> 25 | r = pfx + prefix + [String! id] 26 | id++ 27 | r 28 | 29 | ;; gensym = GenSym{"ȣ"} 30 | gensym = GenSym{"$$"} 31 | 32 | 33 | identity{x} = x 34 | 35 | 36 | binsearch{xs, x} = 37 | ;; Find an insertion point for x in the sorted array xs. 38 | ;; Returns an index i such that 39 | ;; xs[i - 1] < x <= xs[i] 40 | ;; In particular, 41 | ;; If x < xs[0] ==> return 0 42 | ;; If x > xs[xs.length - 1] ==> return xs.length 43 | ;; Take note that 44 | ;; If x == xs[i] ==> return i + 1 45 | ;; The return value should not be interpreted as the index where x 46 | ;; is found, but some index where x can be safely spliced to 47 | ;; preserve the array's sortedness. 48 | var lo = 0 49 | var hi = xs.length - 1 50 | while [lo <= hi]: 51 | mid = lo + [[hi - lo] >> 1] 52 | v = xs[mid] 53 | match xs[mid]: 54 | [< x] -> 55 | set-var lo = mid + 1 56 | [> x] -> 57 | set-var hi = mid - 1 58 | [_] -> 59 | return [mid + 1] 60 | lo 61 | 62 | 63 | classify{*classes, var xs} = 64 | ;; Classify a list of lists accordingly to the first element 65 | ;; of the list. The categories must be listed explicitly 66 | ;; and any element that doesn't fit is put in the rest field 67 | ;; of the return value. 68 | ;; Example: 69 | ;; classify{.a, .b, {#a{1}, #b{2}, #a{3}, #a{4}, #c{5}}} 70 | ;; ==> {a = {1, 2}, b = {2}, rest = {#c{5}}} 71 | 72 | results = {rest = {}} 73 | classes each cls -> 74 | results[cls] = {} 75 | while xs.length: 76 | match xs.shift{}: 77 | #splice{*newxs} -> 78 | set-var xs = newxs ++ xs 79 | #ignore -> 80 | null 81 | {cls, x} when results[cls] -> 82 | results[cls].push with x 83 | other -> 84 | results.rest.push with other 85 | results 86 | 87 | 88 | classify_contiguous{xs, classifier} = 89 | ;; Split xs according to a predicate, preserving the 90 | ;; order. Contiguous elements with the same category are put 91 | ;; together. 92 | ;; Example: 93 | ;; classify_contiguous{{1, 2, 4, 3, 5}, {x} -> x mod 2 == 0} 94 | ;; ==> {{false, 1}, {true, 2, 4}, {false, 3, 5}} 95 | 96 | groups = {} 97 | var currcls = null 98 | var curr = null 99 | xs each x -> 100 | cls = classifier{x} 101 | if [cls === currcls]: 102 | then: curr.push with x 103 | else: 104 | if curr: 105 | groups.push with curr 106 | set-var curr = {cls, x} 107 | set-var currcls = cls 108 | if curr: 109 | groups.push with curr 110 | groups 111 | 112 | 113 | ;; _neighbours{match} = 114 | ;; ;; Takes an array and returns an array of pairs of consecutive elements. 115 | ;; ;; Example: 116 | ;; ;; neighbours{{1, 7, 10, 3, 7}} 117 | ;; ;; ==> {{1, 7}, {7, 10}, {10, 3}, {3, 7}} 118 | 119 | ;; {} -> {} 120 | ;; {x} -> {} 121 | ;; {x, y, *rest} -> 122 | ;; {{x, y}} ++ _neighbours{{y} ++ rest} 123 | 124 | 125 | partition{xs, predicate} = 126 | ;; Partition a list according to a predicate 127 | ;; Example: 128 | ;; partition{{1, 2, 4, 5, 16}, {x} -> x mod 2} 129 | ;; ==> {{1, 5}, {2, 4, 16}} 130 | 131 | t = {} 132 | f = {} 133 | xs each 134 | x when predicate{x} -> t.push{x} 135 | x -> f.push{x} 136 | {t, f} 137 | 138 | 139 | ;; product{a, b} = 140 | ;; var results = {} 141 | ;; a each x -> 142 | ;; results ++= 143 | ;; b each y -> {x, y} 144 | ;; results 145 | 146 | 147 | construct{match, fn, zero} = 148 | {} -> zero 149 | {x} -> x 150 | {x, *rest} -> 151 | fn{x, construct{rest, fn, zero}} 152 | 153 | 154 | mkset{xs} = 155 | rval = {=} 156 | xs each x -> 157 | rval[x] = true 158 | rval 159 | 160 | 161 | Body{match x} = 162 | #multi{*xs} -> xs 163 | else -> {x} 164 | 165 | 166 | camelCase{x} = 167 | if x.indexOf{"-"} == -1: 168 | x 169 | else: 170 | x.replace{R.g"-([A-Za-z0-9_])", {_, m} -> m.toUpperCase{}} 171 | 172 | invCamelCase{x} = 173 | x.replace{R.g"([a-z0-9])([A-Z]+)"} with {_, m1, m2} -> 174 | m1 + "-" + m2.toLowerCase{} 175 | 176 | 177 | 178 | mac1{f, name = null} = 179 | #macro with {context, scope, form, match} -> 180 | #data{expr} -> 181 | f{expr} 182 | #void{} when name -> 183 | #variable{name} 184 | 185 | __chk_ncache = {=} 186 | __chk_scache = {=} 187 | 188 | checker_db{match} = 189 | null? -> checker_db.null 190 | undefined? -> checker_db.undefined 191 | ===true -> checker_db.true 192 | ===false -> checker_db.false 193 | Number? n -> 194 | ;; I believe that the reason why we are caching these macros is 195 | ;; so that they can be compared with ==. This is done when 196 | ;; optimizing patterns for example. I wrote this way after the 197 | ;; fact, so I'm not 100% sure, but that's the only explanation I 198 | ;; can think of. There's probably a better way to do all this. 199 | if [__chk_ncache[n]]: 200 | then: __chk_ncache[n] 201 | else: 202 | v = mac1{{x} -> `[^x === ^=n]`} 203 | __chk_ncache[n] = v 204 | v 205 | String? s -> 206 | if Object.prototype.hasOwnProperty.call{__chk_scache, s}: 207 | then: __chk_scache[s] 208 | else: 209 | v = mac1{{x} -> `[^x === ^=s]`} 210 | __chk_scache[s] = v 211 | v 212 | 213 | checker_db &: { 214 | String = mac1{f, .String} where f{x} = `[typeof{^x} === "string"]` 215 | Number = mac1{f, .Number} where f{x} = `[typeof{^x} === "number"]` 216 | ;; Array = mac1{f} where f{x} = `[[instanceof]{^x, Array}]` 217 | Array = mac1{f, .Array} where f{x} = `Array.isArray{^x}` 218 | true = mac1{f, .true} where f{x} = x 219 | false = mac1{f, .false} where f{x} = `[not ^x]` 220 | null = mac1{f, .null} where f{x} = `[^x === ^=null]` 221 | undefined = mac1{f, .undefined} where f{x} = `[^x === ^=undefined]` 222 | } 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /src/version.eg: -------------------------------------------------------------------------------- 1 | 2 | require: 3 | ..package -> version 4 | 5 | provide: 6 | version 7 | -------------------------------------------------------------------------------- /test/feature_test.eg: -------------------------------------------------------------------------------- 1 | 2 | requireMacros: 3 | "earl-mocha" -> 4 | describe, it, before, after, assert, asserts, expectError 5 | 6 | 7 | describe "examples": 8 | it "fibonacci": 9 | fib{match} = 10 | 0 -> 0 11 | 1 -> 1 12 | n -> fib{n - 1} + fib{n - 2} 13 | assert fib{3} === 2 14 | assert fib{10} === 55 15 | 16 | 17 | describe "Invariances": 18 | asserts: 19 | `a b` == `a[b]` 20 | `a b` == `[a][b]` 21 | `a b c` == `a [b c]` 22 | `a[{x}]` == `a{x}` 23 | `[[1]]` == `1` 24 | `a: b` == `a{b}` 25 | `a b: c` == `a{b, c}` 26 | 27 | describe "Arithmetic": 28 | asserts: 29 | [1 + 2 * 3] === 7 30 | [1 * 2 + 3] === 5 31 | [70 / 10 / 7] === 1 32 | [2 ** 3 ** 2] === 512 33 | 34 | describe "Operator priority": 35 | asserts: 36 | `a + b + c` == `[a + b] + c` 37 | `a * b + c` == `[a * b] + c` 38 | `a + b * c` == `a + [b * c]` 39 | 40 | describe "Conditionals": 41 | it "if/then/else": 42 | positivity{x} = 43 | if [x > 0]: 44 | then: .positive 45 | else: 46 | if [x < 0]: 47 | then: .negative 48 | else: .zero 49 | 50 | assert positivity{0} === .zero 51 | assert positivity{11} === .positive 52 | assert positivity{-41} === .negative 53 | 54 | it "if/elif/else": 55 | positivity{x} = 56 | if [x > 0]: 57 | .positive 58 | elif [x < 0]: 59 | .negative 60 | else: 61 | .zero 62 | 63 | assert positivity{0} === .zero 64 | assert positivity{11} === .positive 65 | assert positivity{-41} === .negative 66 | 67 | 68 | describe "Pattern matching": 69 | 70 | describe "basic types": 71 | 72 | asserts "String": 73 | String? "hello" 74 | not String? 1 75 | [String! 123] === "123" 76 | 77 | asserts "Number": 78 | Number? 1 79 | Number? 7.23e-65 80 | not Number? "123" 81 | [Number! "123"] === 123 82 | 83 | asserts "Boolean": 84 | Boolean? true 85 | not Boolean? 0 86 | [Boolean! 0] === false 87 | [Boolean! 1] === true 88 | [Boolean! ""] === false 89 | [Boolean! {}] === true 90 | [Boolean! "quack"] === true 91 | 92 | asserts "Array": 93 | Array? {1, 2, 3} 94 | not Array? 1 95 | [Array! 1] == {1} 96 | [Array! {1, 2, 3}] == {1, 2, 3} 97 | 98 | asserts "#struct": 99 | #data? #data{.a, .b, .c} 100 | not [#data? #dat{.a, .b, .c}] 101 | [#data! {1, 2}] == #data{{1, 2}} 102 | [#data! #data{1, 2}] == #data{1, 2} 103 | [#data! 1] == #data{1} 104 | 105 | it "match on #struct": 106 | calc{match} = 107 | Number? n -> n 108 | #add{m, n} -> calc{m} + calc{n} 109 | #sub{m, n} -> calc{m} - calc{n} 110 | #mul{m, n} -> calc{m} * calc{n} 111 | #div{m, n} -> calc{m} / calc{n} 112 | #sub{n} -> -calc{n} 113 | assert [calc{x} === 10] where 114 | x = #mul{5, 2} 115 | assert [calc{x} === -7] where 116 | x = #div{#add{1, 13}, #sub{2}} 117 | 118 | it "comparisons": 119 | compare{match, threshold} = 120 | [> threshold] -> "above" 121 | [< threshold] -> "below" 122 | [=== threshold] -> "equal" 123 | 124 | assert compare{-41, 0} === "below" 125 | assert compare{11, 0} === "above" 126 | assert compare{9, 9} === "equal" 127 | 128 | describe "destructuring assignment": 129 | it "simple": 130 | {{a, b}, c} = {{1, 2}, 3} 131 | assert [a + b + c] === 6 132 | it "bounds checks": 133 | expectError Error: 134 | let {a} = {11, 22} 135 | expectError Error: 136 | let {a, b, c} = {11, 22} 137 | 138 | it "match sub-clauses": 139 | tr{match} = 140 | String? s -> s 141 | Number? n -> String{n} 142 | #send{f, match} -> 143 | String? s -> tr{f} + "." + s 144 | #data{*args} -> tr{f} + "{" + args.join{", "} + "}" 145 | other -> throw "illegal expression" 146 | 147 | assert tr{x} === "a.b" where x = #send{"a", "b"} 148 | assert tr{x} === "a{b, 12}" where x = #send{"a", #data{"b", 12}} 149 | 150 | 151 | describe "Exception handing": 152 | it "catch": 153 | assert [null.x and false !! TypeError? -> true] 154 | it "throw": 155 | assert 156 | [throw .hello] !! 157 | .hello -> true 158 | other -> false 159 | assert 160 | [throw .not_hello] !! 161 | .hello -> false 162 | other -> true 163 | 164 | describe "Regular expressons": 165 | before: 166 | @re = R"ab*a" 167 | it "test match": 168 | {"aa", "aba", "abba", "aadvark", "cabbage"} each 169 | @re? x -> pass 170 | x -> throw E.failure{x} 171 | it "test not match": 172 | {"a", "bachi", "bouzouk"} each 173 | @re? x -> throw E.failure{x} 174 | x -> pass 175 | 176 | it "chain": 177 | assert "7654321" === 178 | chain {1, 2, 3}: 179 | @concat with {4, 5} 180 | @reverse{} 181 | {7, 6}.concat{@} 182 | @join{""} 183 | 184 | 185 | class Person: 186 | constructor{String? name, Number! age} = 187 | @name = name 188 | @age = age 189 | descr{} = 190 | @name + ":" + [String! @age] 191 | descr2{} = 192 | @descr{}.replace{":", "~"} 193 | 194 | describe "class": 195 | it "one": 196 | let one = new Person{.peter, 12} 197 | assert Person? one 198 | assert one.name === .peter 199 | assert one.age === 12 200 | assert one.descr{} === "peter:12" 201 | it "two": 202 | let two = Person{.igor, "34"} 203 | assert Person? two 204 | assert two.name === .igor 205 | assert two.age === 34 206 | assert two.age !== "34" 207 | assert two.descr2{} === "igor~34" 208 | it "match constructor": 209 | expectError Error: Person{12, 12} 210 | asserts "misc": 211 | not Person? {.peter, 12} 212 | not Person? {name = .peter, age = 12} 213 | -------------------------------------------------------------------------------- /test/macros.eg: -------------------------------------------------------------------------------- 1 | provide: 2 | add-two-macro 3 | try-expand 4 | 5 | 6 | ast-as-array(ast) = 7 | let contents = ast.map with match -> 8 | Array? arr -> ast-as-array{arr} 9 | x -> #value{x} 10 | #data{*contents} 11 | 12 | 13 | macro try-expand(expr) = 14 | try: 15 | let expanded-ast = @expand(@context, expr) 16 | catch err: 17 | let msg = '{err.name}: {err.message}' 18 | return `{false, ^=msg}` 19 | `{true, ^ast-as-array(expanded-ast)}` 20 | 21 | 22 | add-two(x) = x + 1 23 | 24 | 25 | macro{add-two} add-two-macro(#data{#value{Number? v}}) = 26 | let {=> add-two} = @deps 27 | ``` 28 | [^add-two](^=v) 29 | ``` 30 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --compilers eg:./register 2 | -------------------------------------------------------------------------------- /test/test-deconstruct.eg: -------------------------------------------------------------------------------- 1 | 2 | requireMacros: 3 | "earl-mocha" -> 4 | describe, it, before, after, assert, asserts, expectError 5 | 6 | 7 | describe "array deconstruction": 8 | 9 | it "basic": 10 | {x, y, z} = {1, 2, 3} 11 | assert {x, y, z} == {1, 2, 3} 12 | 13 | it "error on wrong length": 14 | expect-error [E.match?]: 15 | {x, y, z} = {1, 2} 16 | pass 17 | expect-error [E.match?]: 18 | {x, y} = {1, 2, 3} 19 | pass 20 | 21 | it "literals": 22 | do: 23 | {x, y, 3} = {1, 2, 3} 24 | assert {x, y} == {1, 2} 25 | do: 26 | expect-error [E.match?]: 27 | {x, y, 3} = {1, 2, 4} 28 | 29 | it "default values": 30 | do: 31 | {x, y, z = 3} = {1, 2, 10} 32 | assert z == 10 33 | do: 34 | {x, y, z = 3} = {1, 2} 35 | assert z == 3 36 | do: 37 | {x, y = 3, z} = {1, 2} 38 | assert y == 3 39 | do: 40 | {x = 3, y, z} = {1, 2} 41 | assert x == 3 42 | 43 | it "nesting": 44 | {a, {b, c}, {{{d}}}, {e, f, g}} = {1, {2, 3}, {{{4}}}, {5, 6, 7}} 45 | assert {a, b, c, d, e, f, g} == {1, 2, 3, 4, 5, 6, 7} 46 | 47 | 48 | describe "object deconstruction": 49 | 50 | it "basic": 51 | {=> x, => y} = {x = 1, y = 2} 52 | assert {x, y} == {1, 2} 53 | 54 | it "order irrelevant": 55 | {=> y, => x} = {x = 1, y = 2} 56 | assert {x, y} == {1, 2} 57 | 58 | it "change keys": 59 | {a => x, b => y} = {a = 1, b = 2} 60 | assert {x, y} == {1, 2} 61 | 62 | it "deep extraction": 63 | {=> {x}, => {{y}}, => Number? z} = {x = {1}, y = {{2}}, z = 3} 64 | assert {x, y, z} == {1, 2, 3} 65 | 66 | it "deep extraction 2": 67 | {x.y.z => a} = {x = {y = {z = 6}}} 68 | assert a == 6 69 | 70 | it "default values": 71 | do: 72 | {=> x = 3, => y} = {x = 10, y = 7} 73 | assert {x, y} == {10, 7} 74 | do: 75 | {=> x = 3, => y} = {y = 7} 76 | assert {x, y} == {3, 7} 77 | 78 | it "deep extraction defaults": 79 | do: 80 | {x.y.z => a = 777} = {x = {y = {z = 6}}} 81 | assert a == 6 82 | do: 83 | {x.y.z => a = 777} = {x = {y = {C = 6}}} 84 | assert a == 777 85 | do: 86 | {x.y.z => a = 777} = {x = {B = {C = 6}}} 87 | assert a == 777 88 | do: 89 | {x.y.z => a = 777} = {A = {B = {C = 6}}} 90 | assert a == 777 91 | 92 | it "extraction calls": 93 | {f{123} => z} = {f{x} = x * 2} 94 | assert z == 246 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /test/test-globals.eg: -------------------------------------------------------------------------------- 1 | require-macros: 2 | "earl-mocha" -> 3 | describe, it 4 | 5 | 6 | JS_GLOBALS = { 7 | .__dirname 8 | .__filename 9 | .Array 10 | .ArrayBuffer 11 | .Boolean 12 | .Buffer 13 | .clearImmediate 14 | .clearInterval 15 | .clearTimeout 16 | .console 17 | .DataView 18 | .Date 19 | .decodeURI 20 | .decodeURIComponent 21 | .encodeURI 22 | .encodeURIComponent 23 | .Error 24 | .eval 25 | .EvalError 26 | .Float32Array 27 | .Float64Array 28 | .Function 29 | .global 30 | .Infinity 31 | .Int16Array 32 | .Int32Array 33 | .Int8Array 34 | .Intl 35 | .isFinite 36 | .isNaN 37 | .JSON 38 | .Map 39 | .Math 40 | .module 41 | .NaN 42 | .Object 43 | .parseFloat 44 | .parseInt 45 | .process 46 | .Promise 47 | .Proxy 48 | .RangeError 49 | .ReferenceError 50 | .Reflect 51 | .RegExp 52 | .Set 53 | .setImmediate 54 | .setInterval 55 | .setTimeout 56 | .String 57 | .Symbol 58 | .SyntaxError 59 | .this 60 | .TypeError 61 | .Uint16Array 62 | .Uint32Array 63 | .Uint8Array 64 | .Uint8ClampedArray 65 | .URIError 66 | .WeakMap 67 | .WeakSet 68 | } 69 | 70 | 71 | describe "JavaScript and Node.js globals": 72 | JS_GLOBALS each name -> 73 | it 'should provide {name}': 74 | eval(name) 75 | -------------------------------------------------------------------------------- /test/test-macros.eg: -------------------------------------------------------------------------------- 1 | require-macros: 2 | "earl-mocha" -> 3 | assert, describe, it 4 | "./macros" -> 5 | add-two-macro 6 | try-expand 7 | 8 | 9 | describe "macros": 10 | it "should permit kebab-case names in dependencies": 11 | let {success, result} = try-expand(add-two-macro(4)) 12 | assert success 13 | -------------------------------------------------------------------------------- /todo.q: -------------------------------------------------------------------------------- 1 | 2 | This is an ad hoc todo list I keep since the beginning. There's no 3 | order to it and some of the remaining entries may be obsolete or 4 | irrelevant. 5 | 6 | 7 | TODO 8 | ==== 9 | 10 | * Fix `{to-string{} => s} = object` so that it binds properly 11 | * Fix `a.b! c` so that it binds properly 12 | * MAYBE: `{"a", "b"} each @to-upper-case{}` 13 | * MAYBE: `each x -> x` ==> `[@] each x -> x` 14 | * '''a 'b'''' should be equivalent to "a 'b'" 15 | * MAYBE: swap "" and '' to make former interpolate 16 | 17 | * add an easier to use context-based macro form (with typical contexts) 18 | * add getter/setter for properties in classes? 19 | 20 | * match x: ..., then result: ... 21 | * improve match errors 22 | * object each [k => v] -> [k => v + 1] 23 | * true/false/null/undefined should be like ==true/... implicitly in patterns 24 | * object, neighbours, etc. should handle iterators in general 25 | * Make `predicate? x` behave like in a pattern everywhere (exception on no-match) 26 | * perhaps `x! [a -> b, c -> d]` ==> `a -> x! b, c -> x! d` (same for ?) 27 | * define special behavior for a % b in pattern context 28 | * MAYBE: `class C{super}: ...` into `class C < super = ...` 29 | * gen should be rebindable 30 | * ? to return null/error instead of true/false 31 | * ! to return {null/error, value} instead of {true/false, value} 32 | * `using` should work like `with` in Python 33 | * catch and finally clauses for do, match, if, and so on 34 | * repr for generator 35 | 36 | * f{a = 1, ...} and the like should be made more efficient. 37 | 38 | * fallthrough in clauses 39 | 40 | * x! y shouldn't return null when x throws an error 41 | 42 | * allow for async generators 43 | * async! f{match} will not work because of the wrapping. fix it 44 | * some errors are misreported; check try: x, catch: y (with no 45 | variable in the catch). 46 | * Allow catch with no variable for the error. 47 | * await in interactive mode 48 | * insert async/gen automatically if await/yield is seen in the body 49 | [is that a good idea?] 50 | * `macro` should generate #restmacro to allow for its use below its 51 | definition in the same scope 52 | * {[^Symbol.project]{x} = ...} 53 | * A wrapper to print stack traces when calling an async functions 54 | * `global x = 123`? 55 | * Extend functions, e.g. `extend.top! f{x} = ...` and 56 | `extend.bottom! f{x} = ...`, or bind previous function to super... 57 | * New macros should extend existing macros 58 | 59 | * Come up with a reliable way to mix multiple wrapping handlers in 60 | patterns and prevent nonsensical combinations. 61 | * f{each x, match} will complain that it cannot resolve each; figure 62 | out why that happens *exactly* and fix it. 63 | 64 | * The "top" and "mutable" fields of #variable are too easy to lose 65 | track of despite its significance. Change to #variable{name, opts} 66 | or something like that. 67 | 68 | * Produce an error when the same variable is found multiple times in a 69 | pattern 70 | * '[...] should annotate the result with location information, 71 | otherwise embedded R"..." or S[...] do not work. 72 | * Make unconditional transformers for String!, Number! and Boolean! 73 | * maybe use \ for unquote? 74 | * Use ES6 classes 75 | * Use ES6 splats 76 | * match_error could use being more precise 77 | * make sure macros fail in non-supported contexts and don't have blanket 78 | [match context: ..., else -> blah] clauses 79 | * let macros insert setup code at their definition site 80 | * experiment with changing the priority of wide juxtaposition 81 | * make it possible to do "earl compile src -o lib" instead of having 82 | to do "earl compile -o lib src" 83 | * string interpolation, perhaps I"a \[x] b" ==> "a " + x + " b" 84 | * fix nested each so that inner each is evaluated with #expr{.ignore} 85 | if outer each is 86 | 87 | 88 | * f{match.0, match.1} = a -> b -> c ==> f{x, y} = match x: a -> match y: b -> c 89 | 90 | 91 | * try! f{...} = ... ==> f{...} = try: ... 92 | 93 | * Review how `with works: could it be a prefix operator? 94 | * Add a where... or with... operator instead of with, when ... is used? 95 | 96 | * index.eg 97 | 98 | * language definition via: ||||| lang 99 | * Create closures for variables inside loops 100 | * define super for subclasses 101 | * @@ for static methods 102 | 103 | * set a function or arbitrary object as the main export for provide 104 | 105 | * Support this projector: [-> String?] f{String?, String?} = ... 106 | 107 | * pure ASCII repr{...} 108 | * ditch pp submodule? 109 | * print errors properly to a normal console 110 | 111 | * Track types at declaration 112 | 113 | * @prelude 114 | 115 | * Eliminate ++ and -- for increment/decrement? 116 | 117 | * IDEA: ~f{a, b, _} <=> {X} -> {a, b, X} 118 | 119 | * Support: [String? or Number?] x 120 | * Defaults for keyword arguments 121 | 122 | * fix nested chain 123 | 124 | * set up a priority matrix 125 | 126 | * support [x each String?] [maybe not...] 127 | * throw actual Error objects... 128 | 129 | * add way to inject additional behavior to macros 130 | 131 | * treat operator at beginning of line as a continuation 132 | 133 | * Document with comments: src/earl-grey.eg 134 | * Document with comments: src/expand.eg 135 | * Document with comments: src/lex.eg 136 | * Document with comments: src/location.eg 137 | * Document with comments: src/parse.eg 138 | * Document with comments: src/pattern.eg 139 | * Document with comments: src/pp.eg 140 | * Document with comments: src/register.eg 141 | * Document with comments: src/run.eg 142 | * Document with comments: src/stdenv.eg 143 | * Document with comments: src/translate-js.eg 144 | 145 | * Bug: first line in the file starts with spaces => should produce INDENT token 146 | 147 | 148 | DONE 149 | ==== 150 | 151 | X Change behavior of a[b] 152 | X "when" clauses for pattern matching 153 | X Define Struct? 154 | X Support project: String! s 155 | X Define #struct! and #struct? 156 | X Translate == to === and != to !== 157 | X "else" clause for cond 158 | X Support deconstruct: String? {a, b, c} 159 | X Splicing in arrays 160 | X `[f{|>} = ...] ==> `[f{tmp} = tmp |> ...] 161 | X `[f{|>*} = ...] ==> `[f{tmp*} = tmp |> ...] 162 | X each operator 163 | X quote 164 | X true? matches all true things, false? matches all false things 165 | X Define Rx[...]? and Rx[...]! 166 | X !! should re-raise error 167 | X require: macro 168 | X chain: macro 169 | X % macro for html generation 170 | X range operator 171 | X with should seek "..." 172 | X New regular expression syntax 173 | X class: macro 174 | X test: macro (find a better name) (blocktest) 175 | X use .duck for the projector with "?" 176 | X items{...} 177 | X enumerate{...} 178 | X "expr as var" 179 | X rest arguments! 180 | X field extraction in pattern matching: {=> name} = {name = "Peter"} 181 | X default values for arguments in p.m. 182 | X IRRELEVANT try to make #x{y, z} [nearly] as efficient as {.x, y, z} 183 | X Replace [aslist! args] with [#multi! {*args}] 184 | X avoid generating spurious ifs when one of the patterns can't fail 185 | X Change chain to use let 186 | X zip{...} 187 | X add provide: 188 | X unquote in require: 189 | X error when each fails to find a pattern 190 | X add each? 191 | X &+ --> & 192 | X clone operator 193 | X Make & clone first object, so that #a{b} & {env = env} works 194 | X Move == to ===, and implement proper equality for == 195 | X Change % to accept [prop = value] as children [done for React] 196 | X remove instanceof operator 197 | X ? and ! as infix operators 198 | X splice: macro 199 | X product{...} 200 | X revamp the current operator priority mechanism with groups and named "tracks" 201 | X Modify the priority of wide juxtaposition 202 | X Indent regexp should consume comments (I think it's fixed, didn't bother to test) 203 | X Track variable mutability at declaration 204 | X "=" does mutation 205 | X Remove the generation of spurious ";;" 206 | X Error for mismatched brackets 207 | X Make = valid in more contexts 208 | X Fix paths when doing eval 209 | X pass, else 210 | X earlgrey.register 211 | X Document with comments: src/opt.eg 212 | X Document with comments: src/util.eg 213 | X match in the arguments list of class members 214 | X Change exception syntax 215 | X Support single inheritance 216 | 217 | X Preserve names for functions 218 | X Remove := 219 | 220 | X Make ::check etc. non-enumerable 221 | X [require:] inside [macros:] 222 | 223 | X Upgrade neighbours to standard lib 224 | X Make zip work with any number of arguments 225 | X Make neighbours take a `n argument (it is currently only valid for n=2) 226 | X investigate bug where some locations cannot be found 227 | (may be related to a mixup with the new version of ! and ?) 228 | (well, it looks like... it fixed itself? can't reproduce it anymore) 229 | X `if` in expressions should generate ?: 230 | X remove the if{x, y, else{z}} form 231 | X remove `each?` 232 | X improve gensym to be less heavy-handed; one counter per variable 233 | name, perhaps 234 | X make unconditional #project more robust 235 | X FIX: f! x = g{y} will include the code for g{y} twice (once in the 236 | success branch, once in the failure branch) 237 | X Upgrade product to standard lib 238 | X timeit macro 239 | X Make `each` iterate over iterables 240 | X x[1..10] instead of x.slice{1, 10} 241 | X print x 242 | X "::check" => Symbol.check, etc. 243 | X add long strings: """xyz""" 244 | X try: catch: 245 | X f{each x} = x + 1 ==> f{xs} = xs each x -> x + 1 246 | X f{chain} = @replace{.a, .b} ==> f{x} -> chain x: @replace{.a, .b} 247 | X WONTFIX: Compare for equality when the same variable is found multiple times 248 | in a pattern 249 | REASON: it's easy enough to do {x, == x} -> ... 250 | X each* as a generator alternative to each 251 | X [x = [a, b, c]] can be translated as [a, b, c = x]; treat this case 252 | the same way expressions in return positions are treated. 253 | X allow break/continue in list-building `each` by unhoisting the 254 | accum.push(...) as much as possible 255 | NOTE: the solution was simpler: [x = ..., accum.push{x}], and push 256 | the assignment in when translating 257 | X fix obj[m]{...} so that it binds the function to this... 258 | IDEA: obj[m] translates to send(obj, m, true), which returns obj[m].bind(obj) 259 | 260 | 261 | X Declare values in if, e.g. if [x = f{y}]: x 262 | OH: Turns out that already works? I guess it would. 263 | X change the in operator to actually be useful 264 | X Allow declaring variables like "n > 0 = 3" 265 | X Figure out what `{x, y} = {1, 2}` should return 266 | X expression `{x, get, y} = {1, 2, 3}` has value 2 267 | X expression `{x, return, y} = {1, 2, 3}` returns 2 268 | X expression `{x, yield, y} = {1, 2, 3}` yields 2 269 | X info.gettext{node} 270 | X emacro --> macro; macro --> cmacro? 271 | X change macro{ctx, scope, form, expr} to cmacro{ctx, expr} 272 | and make scope and form available in this (only for user code) 273 | X info.mark{*nodes} 274 | X fix emacro's interaction with ! when not in a pattern 275 | X Embed promisify 276 | X quasiquote with `a + b` instead of '[a + b] 277 | X left-priority of `each` should be higher 278 | X source maps 279 | X `is` should be `===` 280 | X maybe replace ... with ??? and make ... an exclusive range 281 | replaced ... with ___ 282 | X raise left-priority of juxtaposition 283 | X outer 284 | X tag scope and restore scope 285 | X empty lhs for -> 286 | X Detect circular references in repr 287 | X {a, b, c = 1} ==> {a, b} & {c = 1, "::insert" = 2} 288 | send{x, y} would transform y into {a, b, {c = 1}} 289 | X `async: non-function` should auto-wrap the code 290 | X MAYBE: gen! f{x} and async! f{x} ==> gen f{x} and async f{x} 291 | X Allow f{=> x, => y} as shortcut for f{{=> x, => y}} (etc.) 292 | X `require` should fail when importing symbols that were not exported 293 | by a module 294 | 295 | X make -l (lazy) a default flag, add -r or -R to override 296 | 297 | X `macro f{x}: ...` should become `macro f{x} = ...` 298 | X revamp the blocktest macro (rename to tests?) 299 | REMOVED IT 300 | X find a way to make macros more importable 301 | idea: macro_require inserts also require(package), which is used to 302 | resolve symbols in the macro's namespace (requires what the macro 303 | is using to be provided, though) 304 | 305 | X Fix `a??.b??{c}` to bind `a.b` properly 306 | X `[x >> x + 1] = 5` ==> x is 6 307 | X print b % x probably shouldn't parse as [print b] % x 308 | X unquote in patterns, e.g. {^Symbol.iterator => it} = ... 309 | X rename get/set macros to something less common? 310 | renamed them expr-value/set-var 311 | 312 | --------------------------------------------------------------------------------