From f33e34a86a92491bfe2969571ec16e30c61ed13c Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Sat, 26 Aug 2017 04:30:36 -0500 Subject: [PATCH 1/6] Starting to get async compilation working --- .babelrc | 11 +- lib/elixir_script/module_systems/namespace.ex | 2 +- lib/elixir_script/passes/output/js_module.ex | 4 +- lib/elixir_script/passes/translate/form.ex | 18 +- .../translate/forms/pattern/patterns.ex | 14 +- .../passes/translate/forms/try.ex | 2 +- .../passes/translate/function.ex | 4 +- lib/elixir_script/passes/translate/helpers.ex | 17 +- .../passes/translate/protocol.ex | 6 +- package.json | 6 +- priv/build/iife/ElixirScript.Core.js | 3173 ++++++++++++++++- rollup.config.js | 8 +- src/javascript/lib/core/special_forms.js | 2 +- test/app/spec/main.spec.js | 4 +- test/support/main.ex | 8 +- yarn.lock | 5 +- 16 files changed, 3234 insertions(+), 50 deletions(-) diff --git a/.babelrc b/.babelrc index 002b4aa0..0c2b576e 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,12 @@ { - "presets": ["env"] + "presets": [ + [ + "env", + { + "targets": { + "node": "current" + } + } + ] + ] } diff --git a/lib/elixir_script/module_systems/namespace.ex b/lib/elixir_script/module_systems/namespace.ex index c98eee87..663110af 100644 --- a/lib/elixir_script/module_systems/namespace.ex +++ b/lib/elixir_script/module_systems/namespace.ex @@ -47,7 +47,7 @@ defmodule ElixirScript.ModuleSystems.Namespace do exports = [JS.return_statement(JS.identifier("__exports"))] make = JS.member_expression( - Helpers.call( + Helpers.call_sync( build_namespace(), [JS.identifier("Elixir"), JS.literal(Enum.join(["Elixir"] ++ Module.split(module_name), "."))] ), diff --git a/lib/elixir_script/passes/output/js_module.ex b/lib/elixir_script/passes/output/js_module.ex index af9f1b2c..5f05c330 100644 --- a/lib/elixir_script/passes/output/js_module.ex +++ b/lib/elixir_script/passes/output/js_module.ex @@ -24,7 +24,7 @@ defmodule ElixirScript.Output.JSModule do J.identifier("Elixir"), J.identifier("start") ), - Helpers.function( + Helpers.arrow_function( [J.identifier(:app), J.identifier(:args)], J.block_statement([ Helpers.call( @@ -51,7 +51,7 @@ defmodule ElixirScript.Output.JSModule do J.identifier("Elixir"), J.identifier("load") ), - Helpers.function( + Helpers.arrow_function( [J.identifier(:module)], J.block_statement([ J.return_statement( diff --git a/lib/elixir_script/passes/translate/form.ex b/lib/elixir_script/passes/translate/form.ex index 767634bf..592c952f 100644 --- a/lib/elixir_script/passes/translate/form.ex +++ b/lib/elixir_script/passes/translate/form.ex @@ -144,17 +144,17 @@ defmodule ElixirScript.Translate.Form do end def compile({:case, _, [condition, [do: clauses]]}, state) do - func = Helpers.call( + ast = Helpers.call( J.member_expression( - Helpers.patterns(), - J.identifier("defmatch") + Helpers.special_forms(), + J.identifier("_case") ), - Enum.map(clauses, fn x -> Clause.compile(x, state) |> elem(0) end) |> List.flatten - ) - - ast = Helpers.call( - J.member_expression( func, J.identifier("call")), - [J.identifier(:this), compile!(condition, state)] + [ + compile!(condition, state), + Enum.map(clauses, fn x -> Clause.compile(x, state) |> elem(0) end) + |> List.flatten + |> J.array_expression() + ] ) { ast, state } diff --git a/lib/elixir_script/passes/translate/forms/pattern/patterns.ex b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex index eb873149..bf55821d 100644 --- a/lib/elixir_script/passes/translate/forms/pattern/patterns.ex +++ b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex @@ -47,49 +47,49 @@ defmodule ElixirScript.Translate.Forms.Pattern.Patterns do end def parameter(name) do - Helpers.call( + Helpers.call_sync( @parameter, [name] ) end def head_tail(headParameter, tailParameter) do - Helpers.call( + Helpers.call_sync( @head_tail, [headParameter, tailParameter] ) end def starts_with(prefix) do - Helpers.call( + Helpers.call_sync( @starts_with, [J.literal(prefix)] ) end def capture(value) do - Helpers.call( + Helpers.call_sync( @capture, [value] ) end def bound(value) do - Helpers.call( + Helpers.call_sync( @bound, [value] ) end def type(prototype, value) do - Helpers.call( + Helpers.call_sync( @_type, [prototype, value] ) end def bitstring_match(values) do - Helpers.call( + Helpers.call_sync( @bitstring_match, values ) diff --git a/lib/elixir_script/passes/translate/forms/try.ex b/lib/elixir_script/passes/translate/forms/try.ex index 249d8f9b..a00d9d7d 100644 --- a/lib/elixir_script/passes/translate/forms/try.ex +++ b/lib/elixir_script/passes/translate/forms/try.ex @@ -70,7 +70,7 @@ defmodule ElixirScript.Translate.Forms.Try do Helpers.call( JS.member_expression( Helpers.patterns(), - JS.identifier("defmatch") + JS.identifier("defmatchAsync") ), processed_clauses ) diff --git a/lib/elixir_script/passes/translate/function.ex b/lib/elixir_script/passes/translate/function.ex index 6a37cd65..04f11805 100644 --- a/lib/elixir_script/passes/translate/function.ex +++ b/lib/elixir_script/passes/translate/function.ex @@ -95,7 +95,7 @@ defmodule ElixirScript.Translate.Function do match_or_default_call = Helpers.call( J.member_expression( Helpers.patterns(), - J.identifier("match_or_default") + J.identifier("match_or_default_async") ), [J.array_expression(patterns), J.identifier("__function_args__"), guards] ) @@ -134,7 +134,7 @@ defmodule ElixirScript.Translate.Function do |> Clause.return_last_statement |> update_last_call(state) - declaration = Helpers.declare_let(params, J.identifier("__arg_matches__")) + declaration = Helpers.declare(params, J.identifier("__arg_matches__")) body = [declaration] ++ body {patterns, params, guard, body} diff --git a/lib/elixir_script/passes/translate/helpers.ex b/lib/elixir_script/passes/translate/helpers.ex index 227eab39..4f88f0b9 100644 --- a/lib/elixir_script/passes/translate/helpers.ex +++ b/lib/elixir_script/passes/translate/helpers.ex @@ -19,18 +19,26 @@ defmodule ElixirScript.Translate.Helpers do ) end - def call(callee, arguments) do + def call_sync(callee, arguments) do J.call_expression( callee, arguments ) end + def call(callee, arguments) do + call_sync(callee, arguments) + |> J.await_expression() + end + def arrow_function(params, body) do J.arrow_function_expression( params, [], - body + body, + false, + false, + true ) end @@ -39,7 +47,10 @@ defmodule ElixirScript.Translate.Helpers do name, params, [], - body + body, + false, + false, + true ) end diff --git a/lib/elixir_script/passes/translate/protocol.ex b/lib/elixir_script/passes/translate/protocol.ex index cfaf4912..34bfeb11 100644 --- a/lib/elixir_script/passes/translate/protocol.ex +++ b/lib/elixir_script/passes/translate/protocol.ex @@ -18,7 +18,7 @@ defmodule ElixirScript.Translate.Protocol do declaration = Helpers.declare( "protocol", - Helpers.call( + Helpers.call_sync( J.member_expression( Helpers.functions(), J.identifier(:defprotocol) @@ -44,12 +44,12 @@ defmodule ElixirScript.Translate.Protocol do Enum.map(impls, fn({impl, impl_for}) -> members = ["Elixir"] ++ Module.split(impl) ++ ["__load"] - ast = Helpers.call( + ast = Helpers.call_sync( Identifier.make_namespace_members(members), [J.identifier("Elixir")] ) - Helpers.call( + Helpers.call_sync( J.member_expression( Helpers.functions(), J.identifier(:defimpl) diff --git a/package.json b/package.json index e1b9d7cb..4423a2a7 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "license": "MIT", "dependencies": { "erlang-types": "^1.0.1", - "tailored": "^2.6.4" + "tailored": "file:/Users/bryanjos/projects/basstype/tailored" }, "devDependencies": { "ava": "^0.21.0", @@ -41,9 +41,7 @@ "sinon": "^2.4.1" }, "ava": { - "require": [ - "babel-register" - ], + "require": ["babel-register"], "babel": { "babelrc": true } diff --git a/priv/build/iife/ElixirScript.Core.js b/priv/build/iife/ElixirScript.Core.js index e4daabe4..de543b31 100644 --- a/priv/build/iife/ElixirScript.Core.js +++ b/priv/build/iife/ElixirScript.Core.js @@ -1,6 +1,3167 @@ -var ElixirScript=function(){'use strict';/* @flow */function type(a,b={}){return new Type(a,b)}function namedVariableResult(a,b){return new NamedVariableResult(a,b)}/* @flow */function is_number(a){return'number'==typeof a}function is_string(a){return'string'==typeof a}function is_boolean(a){return'boolean'==typeof a}function is_symbol(a){return'symbol'==typeof a}function is_object(a){return'object'==typeof a}function is_variable(a){return a instanceof Variable}function is_null(a){return null===a}function is_array(a){return Array.isArray(a)}function is_function(a){return'[object Function]'==Object.prototype.toString.call(a)}function is_map(a){return a instanceof Map}function resolveNull(){return function(a){return is_null(a)}}function resolveWildcard(){return function(){return!0}}function resolveObject(a){let b={};const c=Object.keys(a).concat(Object.getOwnPropertySymbols(a));for(let d of c)b[d]=buildMatch(a[d]);return function(d,e){if(!is_object(d)||a.length>d.length)return!1;for(let a of c)if(!(a in d)||!b[a](d[a],e))return!1;return!0}}function getSize(a,b){return a*b/8}function arraysEqual(c,a){if(c===a)return!0;if(null==c||null==a)return!1;if(c.length!=a.length)return!1;for(var b=0;bf.integer(a));return new f(...b)}function resolveNoMatch(){return function(){return!1}}function buildMatch(a){if(null===a)return resolveNull(a);if('undefined'==typeof a)return resolveWildcard(a);const b=a.constructor.prototype,c=g.get(b);return c?c(a):'object'==typeof a?resolveObject(a):resolveNoMatch()}function defmatchgen(...a){const b=getArityMap(a);return function*(...a){let[c,d]=findMatchingFunction(a,b);return yield*c.apply(this,d)}}function findMatchingFunction(a,b){if(b.has(a.length)){const c=b.get(a.length);let d=null,e=null;for(let b of c){let c=[];a=fillInOptionalValues(a,b.arity,b.optionals);const f=b.pattern(a,c),[g,h]=checkNamedVariables(c);if(f&&h&&b.guard.apply(this,g)){d=b.fn,e=g;break}}if(!d)throw console.error('No match for:',a),new MatchError(a);return[d,e]}throw console.error('Arity of',a.length,'not found. No match for:',a),new MatchError(a)}function getArityMap(a){let b=new Map;for(const c of a){const a=getArityRange(c);for(const d of a){let a=[];b.has(d)&&(a=b.get(d)),a.push(c),b.set(d,a)}}return b}function getArityRange(a){const b=a.arity-a.optionals.length,c=a.arity;let d=[b];for(;d[d.length-1]!=c;)d.push(d[d.length-1]+1);return d}function getOptionalValues(a){let b=[];for(let c=0;c!0,d=null){let e=[],f=buildMatch(a);const g=f(b,e),[h,i]=checkNamedVariables(e);return g&&i&&c.apply(this,h)?h:d}function run_generators(a,b){if(0==b.length)return a.map((a)=>Array.isArray(a)?a:[a]);else{const c=b.pop();let d=[];for(let b of c())for(let c of a)d.push([b].concat(c));return run_generators(d,b)}}function map_to_object(a){const b={};for(const[c,d]of a.entries())b[c]=d instanceof Map?map_to_object(d):d;return b}function split_at(a,b){if(0>b){const c=a.length+b;return 0>c?new s.Tuple('',a):split_at(a,c)}let c='',d='',e=0;for(const f of a)eArray.isArray(a)?a:[a]);const c=b.pop(),d=[];for(const e of c())for(const b of a)d.push([e].concat(b));return run_list_generators(d,b)}// http://erlang.org/doc/man/lists.html -function reverse(a){return[...a]}function flatten(a,b=[]){const c=a.reduce((a,b)=>Array.isArray(b)?a.concat(flatten(b)):a.concat(b),[]);return c.concat(b)}function foldl(a,b,c){return c.reduce((b,c)=>a(c,b),b)}function keyfind(a,b,c){for(const d of c)if(d.get(b-1)===a)return d;return!1}function keydelete(a,b,c){const d=[];let e=!1;for(let f=0;f{if(null===c)return b;return is_integer(c)?b+a(c):is_bitstring$1(c)?b+a(...c.value):b+iolist_to_binary(c)},'');return d}function _throw(a){throw a}function error(a){throw new e.Tuple(a,[])}function exit(...a){if(2===a.length)throw a[1];else throw a[0]}function is_key(a,b){return b.has(a)}function put$1(a,b){return q.get(p).set(a,b),Symbol.for('ok')}function get$1(a){return q.get(p).get(a)}function characters_to_list(a,b=Symbol.for('unicode')){let c=a;return Array.isArray(a)&&(c=i.flatten(a)),k.is_binary(c)?c.split('').map((a)=>a.codePointAt(0)):c.reduce((a,d)=>k.is_integer(d)?a.concat(d):a.concat(characters_to_list(d,b)),[])}function get_key(a){let b=a;if(__elixirscript_names__.has(a)&&(b=__elixirscript_names__.get(a)),__elixirscript_store__.has(b))return b;throw new Error(`Key ${b} not found`)}var a=String.fromCodePoint,b=Number.isInteger;class Variable{constructor(a=null,b=Symbol.for('tailored.no_value')){this.name=a,this.default_value=b}}class Wildcard{constructor(){}}class StartsWith{constructor(a){this.prefix=a}}class Capture{constructor(a){this.value=a}}class HeadTail{constructor(a,b){this.head=a,this.tail=b}}class Type{constructor(a,b={}){this.type=a,this.objPattern=b}}class Bound{constructor(a){this.value=a}}class BitStringMatch{constructor(...a){this.values=a}length(){return values.length}bit_size(){return 8*this.byte_size()}byte_size(){let a=0;for(let b of this.values)a+=b.unit*b.size/8;return a}getValue(a){return this.values(a)}getSizeOfValue(a){let b=this.getValue(a);return b.unit*b.size}getTypeOfValue(a){return this.getValue(a).type}}class NamedVariableResult{constructor(a,b){this.name=a,this.value=b}}class Tuple{constructor(...a){this.values=Object.freeze(a),this.length=this.values.length}get(a){return this.values[a]}count(){return this.values.length}[Symbol.iterator](){return this.values[Symbol.iterator]()}toString(){let a,b='';for(a=0;aBitString$1.integer(a));return new BitString$1(...d)}[Symbol.iterator](){return this.value[Symbol.iterator]()}toString(){var a,b='';for(a=0;a>'}process(a){let b=[];var c;for(c=0;cb?c.push(b):2048>b?c.push(192|b>>6,128|63&b):55296>b||57344<=b?c.push(224|b>>12,128|63&b>>6,128|63&b):(d++,b=65536+((1023&b)<<10|1023&a.charCodeAt(d)),c.push(240|b>>18,128|63&b>>12,128|63&b>>6,128|63&b));return c}static toUTF16Array(a){for(var b,c=[],d=0;d=b?(c.push(0),c.push(b)):(c.push(255&b>>8),c.push(255&b));return c}static toUTF32Array(a){for(var b,c=[],d=0;d=b?(c.push(0),c.push(0),c.push(0),c.push(b)):(c.push(0),c.push(0),c.push(255&b>>8),c.push(255&b));return c}//http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits -static float32ToBytes(a){var b=[],c=new ArrayBuffer(4);new Float32Array(c)[0]=a;let d=new Uint32Array(c)[0];return b.push(255&d>>24),b.push(255&d>>16),b.push(255&d>>8),b.push(255&d),b}static float64ToBytes(a){var b=[],c=new ArrayBuffer(8);new Float64Array(c)[0]=a;var d=new Uint32Array(c)[0],e=new Uint32Array(c)[1];return b.push(255&e>>24),b.push(255&e>>16),b.push(255&e>>8),b.push(255&e),b.push(255&d>>24),b.push(255&d>>16),b.push(255&d>>8),b.push(255&d),b}}var e={Tuple,PID:class PID{constructor(){++c,this.id=c}toString(){return'PID#<0.'+this.id+'.0>'}},Reference:class Reference{constructor(){++d,this.id=d,this.ref=Symbol()}toString(){return'Ref#<0.0.0.'+this.id+'>'}},BitString:BitString$1};/* @flow */const f=e.BitString,g=new Map;g.set(Variable.prototype,function resolveVariable(a){return function(b,c){return null===a.name?c.push(b):!a.name.startsWith('_')&&c.push(namedVariableResult(a.name,b)),!0}}),g.set(Wildcard.prototype,resolveWildcard),g.set(HeadTail.prototype,function resolveHeadTail(a){const b=buildMatch(a.head),c=buildMatch(a.tail);return function(a,d){if(!is_array(a)||0===a.length)return!1;const e=a[0],f=a.slice(1);return b(e,d)&&c(f,d)}}),g.set(StartsWith.prototype,function resolveStartsWith(a){const b=a.prefix;return function(a,c){return is_string(a)&&a.startsWith(b)&&(c.push(a.substring(b.length)),!0)}}),g.set(Capture.prototype,function resolveCapture(a){const b=buildMatch(a.value);return function(a,c){return!!b(a,c)&&(c.push(a),!0)}}),g.set(Bound.prototype,function resolveBound(a){return function(b){return typeof b==typeof a.value&&b===a.value}}),g.set(Type.prototype,function resolveType(a){return function(b,c){if(b instanceof a.type){const d=buildMatch(a.objPattern);return d(b,c)}return!1}}),g.set(BitStringMatch.prototype,function resolveBitString(a){let b=[];for(let c of a.values)if(is_variable(c.value)){let a=getSize(c.unit,c.size);fillArray(b,a)}else b=b.concat(new f(c).value);let c=a.values;return function(a,d){var e=String.fromCharCode;let g=null;if(!is_string(a)&&!(a instanceof f))return!1;g=is_string(a)?new f(f.binary(a)):a;let h=0;for(let f,j=0;jd.size)return!1;for(let a of c)if(!d.has(a)||!b.get(a)(d.get(a),e))return!1;return!0}}),g.set(Array.prototype,function resolveArray(a){const b=a.map((a)=>buildMatch(a));return function(c,d){return is_array(c)&&c.length==a.length&&c.every(function(a,e){return b[e](c[e],d)})}}),g.set(String.prototype,function resolveString(a){return function(b){return is_string(b)&&b===a}}),g.set(Boolean.prototype,function resolveBoolean(a){return function(b){return is_boolean(b)&&b===a}}),g.set(Function.prototype,function resolveFunction(a){return function(b){return is_function(b)&&b===a}}),g.set(Object.prototype,resolveObject);class MatchError extends Error{constructor(a){if(super(),'symbol'==typeof a)this.message='No match for: '+a.toString();else if(Array.isArray(a)){let b=a.map((a)=>null===a?'null':'undefined'==typeof a?'undefined':a.toString());this.message='No match for: '+b}else this.message='No match for: '+a;this.stack=new Error().stack,this.name=this.constructor.name}}class Clause{constructor(a,b,c=()=>!0){this.pattern=buildMatch(a),this.arity=a.length,this.optionals=getOptionalValues(a),this.fn=b,this.guard=c}}const h=Symbol();// https://github.com/airportyh/protomorphism -class Protocol{constructor(a){function createFun(a){return function(...c){const d=c[0];let e=null;if(null===d&&this.hasImplementation(Symbol('null'))?e=this.registry.get(Symbol)[a]:b(d)&&this.hasImplementation(s.Integer)?e=this.registry.get(s.Integer)[a]:'number'==typeof d&&!b(d)&&this.hasImplementation(s.Float)?e=this.registry.get(s.Float)[a]:'string'==typeof d&&this.hasImplementation(s.BitString)?e=this.registry.get(s.BitString)[a]:d&&d instanceof Map&&d.has(Symbol.for('__struct__'))&&this.hasImplementation(d)?e=this.registry.get(d.get(Symbol.for('__struct__')).__MODULE__)[a]:null!==d&&this.hasImplementation(d)?e=this.registry.get(d.constructor)[a]:this.fallback&&(e=this.fallback[a]),null!=e){const a=e.apply(this,c);return a}throw new Error(`No implementation found for ${d}`)}}for(const b in this.registry=new Map,this.fallback=null,a)this[b]=createFun(b).bind(this)}implementation(a,b){null===a?this.fallback=b:this.registry.set(a,b)}hasImplementation(a){if(a===s.Integer||a===s.Float||a===s.BitString)return this.registry.has(a);return a&&a instanceof Map&&a.has(Symbol.for('__struct__'))?this.registry.has(a.get(Symbol.for('__struct__')).__MODULE__):this.registry.has(a.constructor)}}class Recurse{constructor(a){this.func=a}}var i={reverse,foreach:function foreach(a,b){return b.forEach((b)=>a(b)),Symbol.for('ok')},duplicate:function duplicate(a,b){const c=[];for(;c.length{if(d.get(c-1)a.get(c-1)?1:0})},keystore:function keystore(a,b,c,d){const e=[...c];for(let f=0;fa.toString()).join()},map:function map(a,b){return b.map((b)=>a(b))},filter:function filter(a,b){return b.filter((b)=>a(b))},filtermap:function filtermap(a,b){const c=[];for(const d of b){const b=a(d);!0===b?c.push(d):b instanceof e.Tuple&&!0===b.get(0)&&c.push(b.get(1))}return c},member:function member(a,b){for(const c of b)if(c===a)return!0;return!1},all:function all(a,b){for(const c of b)if(!1===a(c))return!1;return!0},any:function any(a,b){for(const c of b)if(!0===a(c))return!0;return!1},splitwith:function splitwith(a,b){let c=!1;const d=[],f=[];for(const e of b)!0==c?f.push(e):!0===a(e)?d.push(e):(c=!0,f.push(e));return new e.Tuple(d,f)},sort:function sort(...a){if(1===a.length){const b=[...a[0]];return b.sort()}const c=a[0],b=[...a[1]];return b.sort((d,a)=>{const b=c(d,a);return!0===b?-1:1})}};// http://erlang.org/doc/man/erlang.html -const j=new e.PID;var k={atom_to_binary,binary_to_atom,binary_to_existing_atom:function binary_to_existing_atom(a,b=Symbol.for('utf8')){return binary_to_atom(a,b)},list_concatenation:function list_concatenation(a,b){return a.concat(b)},list_subtraction:function list_subtraction(a,b){const c=[...a];for(const d of b){const a=c.indexOf(d);-1>b},bxor:function bxor(a,b){return a^b},bnot:function bnot(a){return~a},is_bitstring:is_bitstring$1,is_boolean:is_boolean$1,is_float:function is_float(a){return is_number$1(a)&&!b(a)},is_function:function is_function$1(a){return'function'==typeof a||a instanceof Function},is_integer,is_list:function is_list(a){return Array.isArray(a)},is_map:function is_map$1(a){return a instanceof Map},is_number:is_number$1,is_pid:function is_pid(a){return a instanceof e.PID},is_port:function is_port(){return!1},is_reference:function is_reference(a){return a instanceof e.Reference},is_tuple:function is_tuple(a){return a instanceof e.Tuple},is_atom:function is_atom(a){if(null===a)return!0;return!!is_boolean$1(a)||'symbol'==typeof a||a instanceof Symbol||null!=a.__MODULE__},is_binary,element:function element(a,b){return b.get(a-1)},setelement:function setelement(a,b,c){const d=[...b.values];return d[a-1]=c,new e.Tuple(...d)},make_tuple:function make_tuple(a,b){const c=[];for(let d=0;d{if(null===c)return b;return is_integer(c)?b+a(c):is_bitstring$1(c)?b+a(...c.value):b+c},'');return d}};// http://erlang.org/doc/man/maps.html -const l=Symbol.for('ok'),m=Symbol.for('error'),n=Symbol.for('badmap'),o=Symbol.for('badkey');const p=Symbol.for('elixir_config'),q=new Map;const r=function get_global(){return'undefined'==typeof self?'undefined'==typeof window?'undefined'==typeof global?(console.warn('No global state found'),null):global:window:self}();r.__elixirscript_store__=new Map,r.__elixirscript_names__=new Map;var s={Tuple:e.Tuple,PID:e.PID,BitString:e.BitString,Patterns:{defmatch:function defmatch(...a){const b=getArityMap(a);return function(...a){let[c,d]=findMatchingFunction(a,b);return c.apply(this,d)}},match:function match(a,b,c=()=>!0){let d=[],e=buildMatch(a);const f=e(b,d),[g,h]=checkNamedVariables(d);if(f&&h&&c.apply(this,g))return g;throw console.error('No match for:',b),new MatchError(b)},MatchError,variable:function variable(a=null,b=Symbol.for('tailored.no_value')){return new Variable(a,b)},wildcard:function wildcard(){return new Wildcard},startsWith:function startsWith(a){return new StartsWith(a)},capture:function capture(a){return new Capture(a)},headTail:function headTail(a,b){return new HeadTail(a,b)},type,bound:function bound(a){return new Bound(a)},Clause,clause:function clause(a,b,c=()=>!0){return new Clause(a,b,c)},bitStringMatch:function bitStringMatch(...a){return new BitStringMatch(...a)},match_or_default,defmatchgen,list_comprehension:function list_comprehension(a,b){const c=run_generators(b.pop()(),b);let d=[];for(let e of c)a.guard.apply(this,e)&&d.push(a.fn.apply(this,e));return d},list_generator:function list_generator(a,b){return function(){let c=[];for(let d of b){const b=match_or_default(a,d,()=>!0,h);if(b!=h){const[a]=b;c.push(a)}}return c}},bitstring_generator:function bitstring_generator(a,b){return function(){let c=[],d=b.slice(0,a.byte_size()),e=1;for(;d.byte_size==a.byte_size();){const f=match_or_default(a,d,()=>!0,h);if(f!=h){const[a]=f;c.push(f)}d=b.slice(a.byte_size()*e,a.byte_size()*(e+1)),e++}return c}},bitstring_comprehension:function bitstring_comprehension(a,b){const c=run_generators(b.pop()(),b);let d=[];for(let e of c)a.guard.apply(this,e)&&d.push(a.fn.apply(this,e));return d=d.map((a)=>e.BitString.integer(a)),new e.BitString(...d)},defmatchGen:function defmatchGen(...a){return defmatchgen(...a)},defmatchAsync:function defmatchAsync(...a){const b=getArityMap(a);return async function(...a){if(b.has(a.length)){const c=b.get(a.length);let d=null,e=null;for(let b of c){let c=[];a=fillInOptionalValues(a,b.arity,b.optionals);const f=b.pattern(a,c),[g,h]=checkNamedVariables(c);if(f&&h&&(await b.guard.apply(this,c))){d=b.fn,e=c;break}}if(!d)throw console.error('No match for:',a),new MatchError(a);return d.apply(this,e)}throw console.error('Arity of',a.length,'not found. No match for:',a),new MatchError(a)}}},Integer:class Integer{},Float:class Float{},Functions:{call_property:function call_property(a,b){if(!b)return a instanceof Function||'function'==typeof a?a():a;if(a instanceof Map){let c=null;if(a.has(b)?c=b:a.has(Symbol.for(b))&&(c=Symbol.for(b)),null===c)throw new Error(`Property ${b} not found in ${a}`);return a.get(c)instanceof Function||'function'==typeof a.get(c)?a.get(c)():a.get(c)}let c=null;if('number'==typeof a||'symbol'==typeof a||'boolean'==typeof a||'string'==typeof a?void 0===a[b]?void 0!==a[Symbol.for(b)]&&(c=Symbol.for(b)):c=b:b in a?c=b:Symbol.for(b)in a&&(c=Symbol.for(b)),null===c)throw new Error(`Property ${b} not found in ${a}`);return a[c]instanceof Function||'function'==typeof a[c]?a[c]():a[c]},defprotocol:function defprotocol(a){return new Protocol(a)},defimpl:function defimpl(a,b,c){a.implementation(b,c)},build_namespace:function build_namespace(a,b){let c=b.split('.');const d=a;let e=a;'Elixir'===c[0]&&(c=c.slice(1));for(const d of c)'undefined'==typeof e[d]&&(e[d]={}),e=e[d];return d.__table__=a.__table__||{},d.__table__[Symbol.for(b)]=e,e},map_to_object,trampoline:function trampoline$1(a){let b=a;for(;b&&b instanceof Recurse;)b=b.func();return b},Recurse,split_at},SpecialForms:{_case:function _case(a,b){return s.Patterns.defmatch(...b)(a)},cond:function cond(...a){for(const b of a)if(b[0])return b[1]();throw new Error},_for:function _for(a,b,c,d=[]){let[e,f]=c.into(d);const g=run_list_generators(b.pop()(),b);for(const h of g)a.guard.apply(this,h)&&(e=f(e,new s.Tuple(Symbol.for('cont'),a.fn.apply(this,h))));return f(e,Symbol.for('done'))},_try:function _try(a,b,c,d,e){let f=null;try{f=a()}catch(a){let d=null;if(b)try{return d=b(a),d}catch(a){if(a instanceof s.Patterns.MatchError)throw a}if(c)try{return d=c(a),d}catch(a){if(a instanceof s.Patterns.MatchError)throw a}throw a}finally{e&&e()}if(d)try{return d(f)}catch(a){if(a instanceof s.Patterns.MatchError)throw new Error('No Match Found in Else');throw a}else return f},_with:function _with(...a){let b=[],c=null,d=null;'function'==typeof a[a.length-2]?[c,d]=a.splice(-2):c=a.pop();for(let c=0;c{const[c,d]=b;return a.set(c,d),a},new Map)},keys:function keys(a){return!1===k.is_map(a)?new e.Tuple(n,a):Array.from(a.keys())},values:function values$1(a){return!1===k.is_map(a)?new e.Tuple(n,a):Array.from(a.values())},is_key,put:function put(a,b,c){if(!1===k.is_map(c))return new e.Tuple(n,c);const d=new Map(c);return d.set(a,b),d},merge:function merge(a,b){return!1===k.is_map(a)?new e.Tuple(n,a):!1===k.is_map(b)?new e.Tuple(n,b):new Map([...a,...b])},update:function update(a,b,c){return!1===k.is_map(c)?new e.Tuple(n,c):!1===is_key(a,c)?new e.Tuple(o,a):new Map([...c,[a,b]])},get:function get(...a){const b=a[0],c=a[1];return!1===k.is_map(c)?new e.Tuple(n,c):is_key(b)?c.get(b):3===a.length?a[2]:new e.Tuple(o,b)},take:function take(a,b){if(!1===k.is_map(b))return new e.Tuple(n,b);if(!is_key(a))return m;const c=b.get(a),d=new Map(b);return d.delete(a),new e.Tuple(c,d)}},lists:i,elixir_errors:{warn:function warn(a){const b=a.join('');return console.warn(`warning: ${b}`),Symbol.for('ok')}},io:{put_chars:function put_chars(a,b){const c=k.iolist_to_binary(b);return a===Symbol.for('stderr')?console.error(c):console.log(c),Symbol.for('ok')}},binary:{copy:function copy(a,b=1){return a.repeat(b)},list_to_bin:function list_to_bin(a){return k.list_to_binary(a)}},unicode:{characters_to_list,characters_to_binary:function characters_to_binary(b){const c=characters_to_list(b);return a(...c)}},elixir_config:{new:function _new(a){return q.set(p,new Map),q.get(p).set(p,a),p},delete:function _delete(a){return q.delete(a),!0},put:put$1,get:get$1,update:function update$1(a,b){const c=b(q.get(p).get(a));return put$1(a,c),c},get_and_put:function get_and_put(a,b){const c=get$1(a);return put$1(a,b),c}}};return{Core:s}}(); +var ElixirScript = (function () { +'use strict'; + +/* @flow */ + +class Variable { + constructor(name = null, default_value = Symbol.for('tailored.no_value')) { + this.name = name; + this.default_value = default_value; + } +} + +class Wildcard { + constructor() {} +} + +class StartsWith { + constructor(prefix) { + this.prefix = prefix; + } +} + +class Capture { + constructor(value) { + this.value = value; + } +} + +class HeadTail { + constructor(head, tail) { + this.head = head; + this.tail = tail; + } +} + +class Type { + constructor(type, objPattern = {}) { + this.type = type; + this.objPattern = objPattern; + } +} + +class Bound { + constructor(value) { + this.value = value; + } +} + +class BitStringMatch { + constructor(...values) { + this.values = values; + } + + length() { + return values.length; + } + + bit_size() { + return this.byte_size() * 8; + } + + byte_size() { + let s = 0; + + for (let val of this.values) { + s = s + val.unit * val.size / 8; + } + + return s; + } + + getValue(index) { + return this.values(index); + } + + getSizeOfValue(index) { + let val = this.getValue(index); + return val.unit * val.size; + } + + getTypeOfValue(index) { + return this.getValue(index).type; + } +} + +class NamedVariableResult { + constructor(name, value) { + this.name = name; + this.value = value; + } +} + +function variable(name = null, default_value = Symbol.for('tailored.no_value')) { + return new Variable(name, default_value); +} + +function wildcard() { + return new Wildcard(); +} + +function startsWith(prefix) { + return new StartsWith(prefix); +} + +function capture(value) { + return new Capture(value); +} + +function headTail(head, tail) { + return new HeadTail(head, tail); +} + +function type(type, objPattern = {}) { + return new Type(type, objPattern); +} + +function bound(value) { + return new Bound(value); +} + +function bitStringMatch(...values) { + return new BitStringMatch(...values); +} + +function namedVariableResult(name, value) { + return new NamedVariableResult(name, value); +} + +/* @flow */ + +function is_number(value) { + return typeof value === 'number'; +} + +function is_string(value) { + return typeof value === 'string'; +} + +function is_boolean(value) { + return typeof value === 'boolean'; +} + +function is_symbol(value) { + return typeof value === 'symbol'; +} + +function is_object(value) { + return typeof value === 'object'; +} + +function is_variable(value) { + return value instanceof Variable; +} + +function is_null(value) { + return value === null; +} + +function is_array(value) { + return Array.isArray(value); +} + +function is_function(value) { + return Object.prototype.toString.call(value) == '[object Function]'; +} + +function is_map(value) { + return value instanceof Map; +} + +class Tuple { + constructor(...args) { + this.values = Object.freeze(args); + this.length = this.values.length; + } + + get(index) { + return this.values[index]; + } + + count() { + return this.values.length; + } + + [Symbol.iterator]() { + return this.values[Symbol.iterator](); + } + + toString() { + let i, + s = ''; + for (i = 0; i < this.values.length; i++) { + if (s !== '') { + s += ', '; + } + + const stringToAppend = this.values[i] ? this.values[i].toString() : ''; + + s += stringToAppend; + } + + return '{' + s + '}'; + } + + put_elem(index, elem) { + if (index === this.length) { + let new_values = this.values.concat([elem]); + return new Tuple(...new_values); + } + + let new_values = this.values.concat([]); + new_values.splice(index, 0, elem); + return new Tuple(...new_values); + } + + remove_elem(index) { + let new_values = this.values.concat([]); + new_values.splice(index, 1); + return new Tuple(...new_values); + } +} + +let process_counter = -1; + +class PID { + constructor() { + process_counter = process_counter + 1; + this.id = process_counter; + } + + toString() { + return 'PID#<0.' + this.id + '.0>'; + } +} + +let ref_counter = -1; + +class Reference { + constructor() { + ref_counter = ref_counter + 1; + this.id = ref_counter; + this.ref = Symbol(); + } + + toString() { + return 'Ref#<0.0.0.' + this.id + '>'; + } +} + +class BitString$1 { + constructor(...args) { + this.value = Object.freeze(this.process(args)); + this.length = this.value.length; + this.bit_size = this.length * 8; + this.byte_size = this.length; + } + + get(index) { + return this.value[index]; + } + + count() { + return this.value.length; + } + + slice(start, end = null) { + let s = this.value.slice(start, end); + let ms = s.map(elem => BitString$1.integer(elem)); + return new BitString$1(...ms); + } + + [Symbol.iterator]() { + return this.value[Symbol.iterator](); + } + + toString() { + var i, + s = ''; + for (i = 0; i < this.count(); i++) { + if (s !== '') { + s += ', '; + } + s += this.get(i).toString(); + } + + return '<<' + s + '>>'; + } + + process(bitStringParts) { + let processed_values = []; + + var i; + for (i = 0; i < bitStringParts.length; i++) { + let processed_value = this['process_' + bitStringParts[i].type](bitStringParts[i]); + + for (let attr of bitStringParts[i].attributes) { + processed_value = this['process_' + attr](processed_value); + } + + processed_values = processed_values.concat(processed_value); + } + + return processed_values; + } + + process_integer(value) { + return value.value; + } + + process_float(value) { + if (value.size === 64) { + return BitString$1.float64ToBytes(value.value); + } else if (value.size === 32) { + return BitString$1.float32ToBytes(value.value); + } + + throw new Error('Invalid size for float'); + } + + process_bitstring(value) { + return value.value.value; + } + + process_binary(value) { + return BitString$1.toUTF8Array(value.value); + } + + process_utf8(value) { + return BitString$1.toUTF8Array(value.value); + } + + process_utf16(value) { + return BitString$1.toUTF16Array(value.value); + } + + process_utf32(value) { + return BitString$1.toUTF32Array(value.value); + } + + process_signed(value) { + return new Uint8Array([value])[0]; + } + + process_unsigned(value) { + return value; + } + + process_native(value) { + return value; + } + + process_big(value) { + return value; + } + + process_little(value) { + return value.reverse(); + } + + process_size(value) { + return value; + } + + process_unit(value) { + return value; + } + + static integer(value) { + return BitString$1.wrap(value, { type: 'integer', unit: 1, size: 8 }); + } + + static float(value) { + return BitString$1.wrap(value, { type: 'float', unit: 1, size: 64 }); + } + + static bitstring(value) { + return BitString$1.wrap(value, { + type: 'bitstring', + unit: 1, + size: value.bit_size + }); + } + + static bits(value) { + return BitString$1.bitstring(value); + } + + static binary(value) { + return BitString$1.wrap(value, { + type: 'binary', + unit: 8, + size: value.length + }); + } + + static bytes(value) { + return BitString$1.binary(value); + } + + static utf8(value) { + return BitString$1.wrap(value, { type: 'utf8', unit: 1, size: value.length }); + } + + static utf16(value) { + return BitString$1.wrap(value, { + type: 'utf16', + unit: 1, + size: value.length * 2 + }); + } + + static utf32(value) { + return BitString$1.wrap(value, { + type: 'utf32', + unit: 1, + size: value.length * 4 + }); + } + + static signed(value) { + return BitString$1.wrap(value, {}, 'signed'); + } + + static unsigned(value) { + return BitString$1.wrap(value, {}, 'unsigned'); + } + + static native(value) { + return BitString$1.wrap(value, {}, 'native'); + } + + static big(value) { + return BitString$1.wrap(value, {}, 'big'); + } + + static little(value) { + return BitString$1.wrap(value, {}, 'little'); + } + + static size(value, count) { + return BitString$1.wrap(value, { size: count }); + } + + static unit(value, count) { + return BitString$1.wrap(value, { unit: count }); + } + + static wrap(value, opt, new_attribute = null) { + let the_value = value; + + if (!(value instanceof Object)) { + the_value = { value: value, attributes: [] }; + } + + the_value = Object.assign(the_value, opt); + + if (new_attribute) { + the_value.attributes.push(new_attribute); + } + + return the_value; + } + + static toUTF8Array(str) { + var utf8 = []; + for (var i = 0; i < str.length; i++) { + var charcode = str.charCodeAt(i); + if (charcode < 0x80) { + utf8.push(charcode); + } else if (charcode < 0x800) { + utf8.push(0xc0 | charcode >> 6, 0x80 | charcode & 0x3f); + } else if (charcode < 0xd800 || charcode >= 0xe000) { + utf8.push(0xe0 | charcode >> 12, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); + } else { + // surrogate pair + i++; + // UTF-16 encodes 0x10000-0x10FFFF by + // subtracting 0x10000 and splitting the + // 20 bits of 0x0-0xFFFFF into two halves + charcode = 0x10000 + ((charcode & 0x3ff) << 10 | str.charCodeAt(i) & 0x3ff); + utf8.push(0xf0 | charcode >> 18, 0x80 | charcode >> 12 & 0x3f, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); + } + } + return utf8; + } + + static toUTF16Array(str) { + var utf16 = []; + for (var i = 0; i < str.length; i++) { + var codePoint = str.codePointAt(i); + + if (codePoint <= 255) { + utf16.push(0); + utf16.push(codePoint); + } else { + utf16.push(codePoint >> 8 & 0xff); + utf16.push(codePoint & 0xff); + } + } + return utf16; + } + + static toUTF32Array(str) { + var utf32 = []; + for (var i = 0; i < str.length; i++) { + var codePoint = str.codePointAt(i); + + if (codePoint <= 255) { + utf32.push(0); + utf32.push(0); + utf32.push(0); + utf32.push(codePoint); + } else { + utf32.push(0); + utf32.push(0); + utf32.push(codePoint >> 8 & 0xff); + utf32.push(codePoint & 0xff); + } + } + return utf32; + } + + //http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits + static float32ToBytes(f) { + var bytes = []; + + var buf = new ArrayBuffer(4); + new Float32Array(buf)[0] = f; + + let intVersion = new Uint32Array(buf)[0]; + + bytes.push(intVersion >> 24 & 0xff); + bytes.push(intVersion >> 16 & 0xff); + bytes.push(intVersion >> 8 & 0xff); + bytes.push(intVersion & 0xff); + + return bytes; + } + + static float64ToBytes(f) { + var bytes = []; + + var buf = new ArrayBuffer(8); + new Float64Array(buf)[0] = f; + + var intVersion1 = new Uint32Array(buf)[0]; + var intVersion2 = new Uint32Array(buf)[1]; + + bytes.push(intVersion2 >> 24 & 0xff); + bytes.push(intVersion2 >> 16 & 0xff); + bytes.push(intVersion2 >> 8 & 0xff); + bytes.push(intVersion2 & 0xff); + + bytes.push(intVersion1 >> 24 & 0xff); + bytes.push(intVersion1 >> 16 & 0xff); + bytes.push(intVersion1 >> 8 & 0xff); + bytes.push(intVersion1 & 0xff); + + return bytes; + } +} + +var ErlangTypes = { + Tuple, + PID, + Reference, + BitString: BitString$1 +}; + +/* @flow */ + +const BitString = ErlangTypes.BitString; + +function resolveSymbol(pattern) { + return function (value) { + return is_symbol(value) && value === pattern; + }; +} + +function resolveString(pattern) { + return function (value) { + return is_string(value) && value === pattern; + }; +} + +function resolveNumber(pattern) { + return function (value) { + return is_number(value) && value === pattern; + }; +} + +function resolveBoolean(pattern) { + return function (value) { + return is_boolean(value) && value === pattern; + }; +} + +function resolveFunction(pattern) { + return function (value) { + return is_function(value) && value === pattern; + }; +} + +function resolveNull(pattern) { + return function (value) { + return is_null(value); + }; +} + +function resolveBound(pattern) { + return function (value, args) { + if (typeof value === typeof pattern.value && value === pattern.value) { + return true; + } + + return false; + }; +} + +function resolveWildcard() { + return function () { + return true; + }; +} + +function resolveVariable(pattern) { + return function (value, args) { + if (pattern.name === null) { + args.push(value); + } else if (!pattern.name.startsWith('_')) { + args.push(namedVariableResult(pattern.name, value)); + } + + return true; + }; +} + +function resolveHeadTail(pattern) { + const headMatches = buildMatch(pattern.head); + const tailMatches = buildMatch(pattern.tail); + + return function (value, args) { + if (!is_array(value) || value.length === 0) { + return false; + } + + const head = value[0]; + const tail = value.slice(1); + + if (headMatches(head, args) && tailMatches(tail, args)) { + return true; + } + + return false; + }; +} + +function resolveCapture(pattern) { + const matches = buildMatch(pattern.value); + + return function (value, args) { + if (matches(value, args)) { + args.push(value); + return true; + } + + return false; + }; +} + +function resolveStartsWith(pattern) { + const prefix = pattern.prefix; + + return function (value, args) { + if (is_string(value) && value.startsWith(prefix)) { + args.push(value.substring(prefix.length)); + return true; + } + + return false; + }; +} + +function resolveType(pattern) { + return function (value, args) { + if (value instanceof pattern.type) { + const matches = buildMatch(pattern.objPattern); + return matches(value, args); + } + + return false; + }; +} + +function resolveArray(pattern) { + const matches = pattern.map(x => buildMatch(x)); + + return function (value, args) { + if (!is_array(value) || value.length != pattern.length) { + return false; + } + + return value.every(function (v, i) { + return matches[i](value[i], args); + }); + }; +} + +function resolveMap(pattern) { + let matches = new Map(); + + const keys = Array.from(pattern.keys()); + + for (let key of keys) { + matches.set(key, buildMatch(pattern.get(key))); + } + + return function (value, args) { + if (!is_map(value) || pattern.size > value.size) { + return false; + } + + for (let key of keys) { + if (!value.has(key) || !matches.get(key)(value.get(key), args)) { + return false; + } + } + + return true; + }; +} + +function resolveObject(pattern) { + let matches = {}; + + const keys = Object.keys(pattern).concat(Object.getOwnPropertySymbols(pattern)); + + for (let key of keys) { + matches[key] = buildMatch(pattern[key]); + } + + return function (value, args) { + if (!is_object(value) || pattern.length > value.length) { + return false; + } + + for (let key of keys) { + if (!(key in value) || !matches[key](value[key], args)) { + return false; + } + } + + return true; + }; +} + +function resolveBitString(pattern) { + let patternBitString = []; + + for (let bitstringMatchPart of pattern.values) { + if (is_variable(bitstringMatchPart.value)) { + let size = getSize(bitstringMatchPart.unit, bitstringMatchPart.size); + fillArray(patternBitString, size); + } else { + patternBitString = patternBitString.concat(new BitString(bitstringMatchPart).value); + } + } + + let patternValues = pattern.values; + + return function (value, args) { + let bsValue = null; + + if (!is_string(value) && !(value instanceof BitString)) { + return false; + } + + if (is_string(value)) { + bsValue = new BitString(BitString.binary(value)); + } else { + bsValue = value; + } + + let beginningIndex = 0; + + for (let i = 0; i < patternValues.length; i++) { + let bitstringMatchPart = patternValues[i]; + + if (is_variable(bitstringMatchPart.value) && bitstringMatchPart.type == 'binary' && bitstringMatchPart.size === undefined && i < patternValues.length - 1) { + throw new Error('a binary field without size is only allowed at the end of a binary pattern'); + } + + let size = 0; + let bsValueArrayPart = []; + let patternBitStringArrayPart = []; + size = getSize(bitstringMatchPart.unit, bitstringMatchPart.size); + + if (i === patternValues.length - 1) { + bsValueArrayPart = bsValue.value.slice(beginningIndex); + patternBitStringArrayPart = patternBitString.slice(beginningIndex); + } else { + bsValueArrayPart = bsValue.value.slice(beginningIndex, beginningIndex + size); + patternBitStringArrayPart = patternBitString.slice(beginningIndex, beginningIndex + size); + } + + if (is_variable(bitstringMatchPart.value)) { + switch (bitstringMatchPart.type) { + case 'integer': + if (bitstringMatchPart.attributes && bitstringMatchPart.attributes.indexOf('signed') != -1) { + args.push(new Int8Array([bsValueArrayPart[0]])[0]); + } else { + args.push(new Uint8Array([bsValueArrayPart[0]])[0]); + } + break; + + case 'float': + if (size === 64) { + args.push(Float64Array.from(bsValueArrayPart)[0]); + } else if (size === 32) { + args.push(Float32Array.from(bsValueArrayPart)[0]); + } else { + return false; + } + break; + + case 'bitstring': + args.push(createBitString(bsValueArrayPart)); + break; + + case 'binary': + args.push(String.fromCharCode.apply(null, new Uint8Array(bsValueArrayPart))); + break; + + case 'utf8': + args.push(String.fromCharCode.apply(null, new Uint8Array(bsValueArrayPart))); + break; + + case 'utf16': + args.push(String.fromCharCode.apply(null, new Uint16Array(bsValueArrayPart))); + break; + + case 'utf32': + args.push(String.fromCharCode.apply(null, new Uint32Array(bsValueArrayPart))); + break; + + default: + return false; + } + } else if (!arraysEqual(bsValueArrayPart, patternBitStringArrayPart)) { + return false; + } + + beginningIndex = beginningIndex + size; + } + + return true; + }; +} + +function getSize(unit, size) { + return unit * size / 8; +} + +function arraysEqual(a, b) { + if (a === b) return true; + if (a == null || b == null) return false; + if (a.length != b.length) return false; + + for (var i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) return false; + } + + return true; +} + +function fillArray(arr, num) { + for (let i = 0; i < num; i++) { + arr.push(0); + } +} + +function createBitString(arr) { + let integerParts = arr.map(elem => BitString.integer(elem)); + return new BitString(...integerParts); +} + +function resolveNoMatch() { + return function () { + return false; + }; +} + +const patternMap = new Map(); +patternMap.set(Variable.prototype, resolveVariable); +patternMap.set(Wildcard.prototype, resolveWildcard); +patternMap.set(HeadTail.prototype, resolveHeadTail); +patternMap.set(StartsWith.prototype, resolveStartsWith); +patternMap.set(Capture.prototype, resolveCapture); +patternMap.set(Bound.prototype, resolveBound); +patternMap.set(Type.prototype, resolveType); +patternMap.set(BitStringMatch.prototype, resolveBitString); +patternMap.set(Number.prototype, resolveNumber); +patternMap.set(Symbol.prototype, resolveSymbol); +patternMap.set(Map.prototype, resolveMap); +patternMap.set(Array.prototype, resolveArray); +patternMap.set(String.prototype, resolveString); +patternMap.set(Boolean.prototype, resolveBoolean); +patternMap.set(Function.prototype, resolveFunction); +patternMap.set(Object.prototype, resolveObject); + +function buildMatch(pattern) { + if (pattern === null) { + return resolveNull(pattern); + } + + if (typeof pattern === 'undefined') { + return resolveWildcard(pattern); + } + + const type$$1 = pattern.constructor.prototype; + const resolver = patternMap.get(type$$1); + + if (resolver) { + return resolver(pattern); + } + + if (typeof pattern === 'object') { + return resolveObject(pattern); + } + + return resolveNoMatch(); +} + +class MatchError extends Error { + constructor(arg) { + super(); + + if (typeof arg === 'symbol') { + this.message = 'No match for: ' + arg.toString(); + } else if (Array.isArray(arg)) { + let mappedValues = arg.map(x => { + if (x === null) { + return 'null'; + } else if (typeof x === 'undefined') { + return 'undefined'; + } + + return x.toString(); + }); + + this.message = 'No match for: ' + mappedValues; + } else { + this.message = 'No match for: ' + arg; + } + + this.stack = new Error().stack; + this.name = this.constructor.name; + } +} + +class Clause { + constructor(pattern, fn, guard = () => true) { + this.pattern = buildMatch(pattern); + this.arity = pattern.length; + this.optionals = getOptionalValues(pattern); + this.fn = fn; + this.guard = guard; + } +} + +function clause(pattern, fn, guard = () => true) { + return new Clause(pattern, fn, guard); +} + + + +function defmatch(...clauses) { + const arities = getArityMap(clauses); + + return function (...args) { + let [funcToCall, params] = findMatchingFunction(args, arities); + return funcToCall.apply(this, params); + }; +} + +function defmatchgen(...clauses) { + const arities = getArityMap(clauses); + + return function* (...args) { + let [funcToCall, params] = findMatchingFunction(args, arities); + return yield* funcToCall.apply(this, params); + }; +} + +function defmatchGen(...args) { + return defmatchgen(...args); +} + +function defmatchAsync(...clauses) { + const arities = getArityMap(clauses); + + return async function (...args) { + if (arities.has(args.length)) { + const arityClauses = arities.get(args.length); + + let funcToCall = null; + let params = null; + for (let processedClause of arityClauses) { + let result = []; + args = fillInOptionalValues(args, processedClause.arity, processedClause.optionals); + + const doesMatch = processedClause.pattern(args, result); + const [filteredResult, allNamesMatch] = checkNamedVariables(result); + + if (doesMatch && allNamesMatch && (await processedClause.guard.apply(this, filteredResult))) { + funcToCall = processedClause.fn; + params = filteredResult; + break; + } + } + + if (!funcToCall) { + console.error('No match for:', args); + throw new MatchError(args); + } + + return funcToCall.apply(this, params); + } else { + console.error('Arity of', args.length, 'not found. No match for:', args); + throw new MatchError(args); + } + }; +} + +function findMatchingFunction(args, arities) { + if (arities.has(args.length)) { + const arityClauses = arities.get(args.length); + + let funcToCall = null; + let params = null; + for (let processedClause of arityClauses) { + let result = []; + args = fillInOptionalValues(args, processedClause.arity, processedClause.optionals); + + const doesMatch = processedClause.pattern(args, result); + const [filteredResult, allNamesMatch] = checkNamedVariables(result); + + if (doesMatch && allNamesMatch && processedClause.guard.apply(this, filteredResult)) { + funcToCall = processedClause.fn; + params = filteredResult; + break; + } + } + + if (!funcToCall) { + console.error('No match for:', args); + throw new MatchError(args); + } + + return [funcToCall, params]; + } else { + console.error('Arity of', args.length, 'not found. No match for:', args); + throw new MatchError(args); + } +} + +function getArityMap(clauses) { + let map = new Map(); + + for (const clause of clauses) { + const range = getArityRange(clause); + + for (const arity of range) { + let arityClauses = []; + + if (map.has(arity)) { + arityClauses = map.get(arity); + } + + arityClauses.push(clause); + map.set(arity, arityClauses); + } + } + + return map; +} + +function getArityRange(clause) { + const min = clause.arity - clause.optionals.length; + const max = clause.arity; + + let range = [min]; + + while (range[range.length - 1] != max) { + range.push(range[range.length - 1] + 1); + } + + return range; +} + +function getOptionalValues(pattern) { + let optionals = []; + + for (let i = 0; i < pattern.length; i++) { + if (pattern[i] instanceof Variable && pattern[i].default_value != Symbol.for('tailored.no_value')) { + optionals.push([i, pattern[i].default_value]); + } + } + + return optionals; +} + +function fillInOptionalValues(args, arity, optionals) { + if (args.length === arity || optionals.length === 0) { + return args; + } + + if (args.length + optionals.length < arity) { + return args; + } + + let numberOfOptionalsToFill = arity - args.length; + let optionalsToRemove = optionals.length - numberOfOptionalsToFill; + + let optionalsToUse = optionals.slice(optionalsToRemove); + + for (let [index, value] of optionalsToUse) { + args.splice(index, 0, value); + if (args.length === arity) { + break; + } + } + + return args; +} + +function match(pattern, expr, guard = () => true) { + let result = []; + let processedPattern = buildMatch(pattern); + const doesMatch = processedPattern(expr, result); + const [filteredResult, allNamesMatch] = checkNamedVariables(result); + + if (doesMatch && allNamesMatch && guard.apply(this, filteredResult)) { + return filteredResult; + } else { + console.error('No match for:', expr); + throw new MatchError(expr); + } +} + +function checkNamedVariables(results) { + const namesMap = {}; + const filteredResults = []; + + for (let i = 0; i < results.length; i++) { + const current = results[i]; + if (current instanceof NamedVariableResult) { + if (namesMap[current.name] && namesMap[current.name] !== current.value) { + return [results, false]; + } else if (namesMap[current.name] && namesMap[current.name] === current.value) { + filteredResults.push(current.value); + } else { + namesMap[current.name] = current.value; + filteredResults.push(current.value); + } + } else { + filteredResults.push(current); + } + } + + return [filteredResults, true]; +} + +function match_or_default(pattern, expr, guard = () => true, default_value = null) { + let result = []; + let processedPattern = buildMatch(pattern); + const doesMatch = processedPattern(expr, result); + const [filteredResult, allNamesMatch] = checkNamedVariables(result); + + if (doesMatch && allNamesMatch && guard.apply(this, filteredResult)) { + return filteredResult; + } else { + return default_value; + } +} + +async function match_or_default_async(pattern, expr, guard = async () => true, default_value = null) { + let result = []; + let processedPattern = buildMatch(pattern); + const doesMatch = processedPattern(expr, result); + const [filteredResult, allNamesMatch] = checkNamedVariables(result); + const matches = doesMatch && allNamesMatch; + + if (matches && (await guard.apply(this, filteredResult))) { + return filteredResult; + } else { + return default_value; + } +} + +const NO_MATCH = Symbol(); + +function bitstring_generator(pattern, bitstring) { + return function () { + let returnResult = []; + let bsSlice = bitstring.slice(0, pattern.byte_size()); + let i = 1; + + while (bsSlice.byte_size == pattern.byte_size()) { + const result = match_or_default(pattern, bsSlice, () => true, NO_MATCH); + + if (result != NO_MATCH) { + const [value] = result; + returnResult.push(result); + } + + bsSlice = bitstring.slice(pattern.byte_size() * i, pattern.byte_size() * (i + 1)); + + i++; + } + + return returnResult; + }; +} + +function list_generator(pattern, list) { + return function () { + let returnResult = []; + for (let i of list) { + const result = match_or_default(pattern, i, () => true, NO_MATCH); + if (result != NO_MATCH) { + const [value] = result; + returnResult.push(value); + } + } + + return returnResult; + }; +} + +function list_comprehension(expression, generators) { + const generatedValues = run_generators(generators.pop()(), generators); + + let result = []; + + for (let value of generatedValues) { + if (expression.guard.apply(this, value)) { + result.push(expression.fn.apply(this, value)); + } + } + + return result; +} + +function run_generators(generator, generators) { + if (generators.length == 0) { + return generator.map(x => { + if (Array.isArray(x)) { + return x; + } else { + return [x]; + } + }); + } else { + const list = generators.pop(); + + let next_gen = []; + for (let j of list()) { + for (let i of generator) { + next_gen.push([j].concat(i)); + } + } + + return run_generators(next_gen, generators); + } +} + +function bitstring_comprehension(expression, generators) { + const generatedValues = run_generators(generators.pop()(), generators); + + let result = []; + + for (let value of generatedValues) { + if (expression.guard.apply(this, value)) { + result.push(expression.fn.apply(this, value)); + } + } + + result = result.map(x => ErlangTypes.BitString.integer(x)); + return new ErlangTypes.BitString(...result); +} + +var Patterns = { + defmatch, + match, + MatchError, + variable, + wildcard, + startsWith, + capture, + headTail, + type, + bound, + Clause, + clause, + bitStringMatch, + match_or_default, + match_or_default_async, + defmatchgen, + list_comprehension, + list_generator, + bitstring_generator, + bitstring_comprehension, + defmatchGen, + defmatchAsync +}; + +class Tuple$2 { + constructor(...args) { + this.values = Object.freeze(args); + this.length = this.values.length; + } + + get(index) { + return this.values[index]; + } + + count() { + return this.values.length; + } + + [Symbol.iterator]() { + return this.values[Symbol.iterator](); + } + + toString() { + let i, + s = ''; + for (i = 0; i < this.values.length; i++) { + if (s !== '') { + s += ', '; + } + + const stringToAppend = this.values[i] ? this.values[i].toString() : ''; + + s += stringToAppend; + } + + return '{' + s + '}'; + } + + put_elem(index, elem) { + if (index === this.length) { + let new_values = this.values.concat([elem]); + return new Tuple$2(...new_values); + } + + let new_values = this.values.concat([]); + new_values.splice(index, 0, elem); + return new Tuple$2(...new_values); + } + + remove_elem(index) { + let new_values = this.values.concat([]); + new_values.splice(index, 1); + return new Tuple$2(...new_values); + } +} + +let process_counter$1 = -1; + +class PID$2 { + constructor() { + process_counter$1 = process_counter$1 + 1; + this.id = process_counter$1; + } + + toString() { + return 'PID#<0.' + this.id + '.0>'; + } +} + +let ref_counter$1 = -1; + +class Reference$2 { + constructor() { + ref_counter$1 = ref_counter$1 + 1; + this.id = ref_counter$1; + this.ref = Symbol(); + } + + toString() { + return 'Ref#<0.0.0.' + this.id + '>'; + } +} + +class BitString$3 { + constructor(...args) { + this.value = Object.freeze(this.process(args)); + this.length = this.value.length; + this.bit_size = this.length * 8; + this.byte_size = this.length; + } + + get(index) { + return this.value[index]; + } + + count() { + return this.value.length; + } + + slice(start, end = null) { + let s = this.value.slice(start, end); + let ms = s.map(elem => BitString$3.integer(elem)); + return new BitString$3(...ms); + } + + [Symbol.iterator]() { + return this.value[Symbol.iterator](); + } + + toString() { + var i, + s = ''; + for (i = 0; i < this.count(); i++) { + if (s !== '') { + s += ', '; + } + s += this.get(i).toString(); + } + + return '<<' + s + '>>'; + } + + process(bitStringParts) { + let processed_values = []; + + var i; + for (i = 0; i < bitStringParts.length; i++) { + let processed_value = this['process_' + bitStringParts[i].type](bitStringParts[i]); + + for (let attr of bitStringParts[i].attributes) { + processed_value = this['process_' + attr](processed_value); + } + + processed_values = processed_values.concat(processed_value); + } + + return processed_values; + } + + process_integer(value) { + return value.value; + } + + process_float(value) { + if (value.size === 64) { + return BitString$3.float64ToBytes(value.value); + } else if (value.size === 32) { + return BitString$3.float32ToBytes(value.value); + } + + throw new Error('Invalid size for float'); + } + + process_bitstring(value) { + return value.value.value; + } + + process_binary(value) { + return BitString$3.toUTF8Array(value.value); + } + + process_utf8(value) { + return BitString$3.toUTF8Array(value.value); + } + + process_utf16(value) { + return BitString$3.toUTF16Array(value.value); + } + + process_utf32(value) { + return BitString$3.toUTF32Array(value.value); + } + + process_signed(value) { + return new Uint8Array([value])[0]; + } + + process_unsigned(value) { + return value; + } + + process_native(value) { + return value; + } + + process_big(value) { + return value; + } + + process_little(value) { + return value.reverse(); + } + + process_size(value) { + return value; + } + + process_unit(value) { + return value; + } + + static integer(value) { + return BitString$3.wrap(value, { type: 'integer', unit: 1, size: 8 }); + } + + static float(value) { + return BitString$3.wrap(value, { type: 'float', unit: 1, size: 64 }); + } + + static bitstring(value) { + return BitString$3.wrap(value, { + type: 'bitstring', + unit: 1, + size: value.bit_size + }); + } + + static bits(value) { + return BitString$3.bitstring(value); + } + + static binary(value) { + return BitString$3.wrap(value, { + type: 'binary', + unit: 8, + size: value.length + }); + } + + static bytes(value) { + return BitString$3.binary(value); + } + + static utf8(value) { + return BitString$3.wrap(value, { type: 'utf8', unit: 1, size: value.length }); + } + + static utf16(value) { + return BitString$3.wrap(value, { + type: 'utf16', + unit: 1, + size: value.length * 2 + }); + } + + static utf32(value) { + return BitString$3.wrap(value, { + type: 'utf32', + unit: 1, + size: value.length * 4 + }); + } + + static signed(value) { + return BitString$3.wrap(value, {}, 'signed'); + } + + static unsigned(value) { + return BitString$3.wrap(value, {}, 'unsigned'); + } + + static native(value) { + return BitString$3.wrap(value, {}, 'native'); + } + + static big(value) { + return BitString$3.wrap(value, {}, 'big'); + } + + static little(value) { + return BitString$3.wrap(value, {}, 'little'); + } + + static size(value, count) { + return BitString$3.wrap(value, { size: count }); + } + + static unit(value, count) { + return BitString$3.wrap(value, { unit: count }); + } + + static wrap(value, opt, new_attribute = null) { + let the_value = value; + + if (!(value instanceof Object)) { + the_value = { value: value, attributes: [] }; + } + + the_value = Object.assign(the_value, opt); + + if (new_attribute) { + the_value.attributes.push(new_attribute); + } + + return the_value; + } + + static toUTF8Array(str) { + var utf8 = []; + for (var i = 0; i < str.length; i++) { + var charcode = str.charCodeAt(i); + if (charcode < 0x80) { + utf8.push(charcode); + } else if (charcode < 0x800) { + utf8.push(0xc0 | charcode >> 6, 0x80 | charcode & 0x3f); + } else if (charcode < 0xd800 || charcode >= 0xe000) { + utf8.push(0xe0 | charcode >> 12, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); + } else { + // surrogate pair + i++; + // UTF-16 encodes 0x10000-0x10FFFF by + // subtracting 0x10000 and splitting the + // 20 bits of 0x0-0xFFFFF into two halves + charcode = 0x10000 + ((charcode & 0x3ff) << 10 | str.charCodeAt(i) & 0x3ff); + utf8.push(0xf0 | charcode >> 18, 0x80 | charcode >> 12 & 0x3f, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); + } + } + return utf8; + } + + static toUTF16Array(str) { + var utf16 = []; + for (var i = 0; i < str.length; i++) { + var codePoint = str.codePointAt(i); + + if (codePoint <= 255) { + utf16.push(0); + utf16.push(codePoint); + } else { + utf16.push(codePoint >> 8 & 0xff); + utf16.push(codePoint & 0xff); + } + } + return utf16; + } + + static toUTF32Array(str) { + var utf32 = []; + for (var i = 0; i < str.length; i++) { + var codePoint = str.codePointAt(i); + + if (codePoint <= 255) { + utf32.push(0); + utf32.push(0); + utf32.push(0); + utf32.push(codePoint); + } else { + utf32.push(0); + utf32.push(0); + utf32.push(codePoint >> 8 & 0xff); + utf32.push(codePoint & 0xff); + } + } + return utf32; + } + + //http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits + static float32ToBytes(f) { + var bytes = []; + + var buf = new ArrayBuffer(4); + new Float32Array(buf)[0] = f; + + let intVersion = new Uint32Array(buf)[0]; + + bytes.push(intVersion >> 24 & 0xff); + bytes.push(intVersion >> 16 & 0xff); + bytes.push(intVersion >> 8 & 0xff); + bytes.push(intVersion & 0xff); + + return bytes; + } + + static float64ToBytes(f) { + var bytes = []; + + var buf = new ArrayBuffer(8); + new Float64Array(buf)[0] = f; + + var intVersion1 = new Uint32Array(buf)[0]; + var intVersion2 = new Uint32Array(buf)[1]; + + bytes.push(intVersion2 >> 24 & 0xff); + bytes.push(intVersion2 >> 16 & 0xff); + bytes.push(intVersion2 >> 8 & 0xff); + bytes.push(intVersion2 & 0xff); + + bytes.push(intVersion1 >> 24 & 0xff); + bytes.push(intVersion1 >> 16 & 0xff); + bytes.push(intVersion1 >> 8 & 0xff); + bytes.push(intVersion1 & 0xff); + + return bytes; + } +} + +var ErlangTypes$1 = { + Tuple: Tuple$2, + PID: PID$2, + Reference: Reference$2, + BitString: BitString$3 +}; + +// https://github.com/airportyh/protomorphism +class Protocol { + constructor(spec) { + this.registry = new Map(); + this.fallback = null; + + function createFun(funName) { + return function (...args) { + const thing = args[0]; + let fun = null; + + if (thing === null && this.hasImplementation(Symbol('null'))) { + fun = this.registry.get(Symbol)[funName]; + } else if (Number.isInteger(thing) && this.hasImplementation(Core.Integer)) { + fun = this.registry.get(Core.Integer)[funName]; + } else if (typeof thing === 'number' && !Number.isInteger(thing) && this.hasImplementation(Core.Float)) { + fun = this.registry.get(Core.Float)[funName]; + } else if (typeof thing === 'string' && this.hasImplementation(Core.BitString)) { + fun = this.registry.get(Core.BitString)[funName]; + } else if (thing && thing instanceof Map && thing.has(Symbol.for('__struct__')) && this.hasImplementation(thing)) { + fun = this.registry.get(thing.get(Symbol.for('__struct__')).__MODULE__)[funName]; + } else if (thing !== null && this.hasImplementation(thing)) { + fun = this.registry.get(thing.constructor)[funName]; + } else if (this.fallback) { + fun = this.fallback[funName]; + } + + if (fun != null) { + const retval = fun.apply(this, args); + return retval; + } + + throw new Error(`No implementation found for ${thing}`); + }; + } + + for (const funName in spec) { + this[funName] = createFun(funName).bind(this); + } + } + + implementation(type, implementation) { + if (type === null) { + this.fallback = implementation; + } else { + this.registry.set(type, implementation); + } + } + + hasImplementation(thing) { + if (thing === Core.Integer || thing === Core.Float || thing === Core.BitString) { + return this.registry.has(thing); + } else if (thing && thing instanceof Map && thing.has(Symbol.for('__struct__'))) { + return this.registry.has(thing.get(Symbol.for('__struct__')).__MODULE__); + } + + return this.registry.has(thing.constructor); + } +} + +function call_property(item, property) { + if (!property) { + if (item instanceof Function || typeof item === 'function') { + return item(); + } + + return item; + } + + if (item instanceof Map) { + let prop = null; + + if (item.has(property)) { + prop = property; + } else if (item.has(Symbol.for(property))) { + prop = Symbol.for(property); + } + + if (prop === null) { + throw new Error(`Property ${property} not found in ${item}`); + } + + if (item.get(prop) instanceof Function || typeof item.get(prop) === 'function') { + return item.get(prop)(); + } + return item.get(prop); + } + + let prop = null; + + if (typeof item === 'number' || typeof item === 'symbol' || typeof item === 'boolean' || typeof item === 'string') { + if (item[property] !== undefined) { + prop = property; + } else if (item[Symbol.for(property)] !== undefined) { + prop = Symbol.for(property); + } + } else if (property in item) { + prop = property; + } else if (Symbol.for(property) in item) { + prop = Symbol.for(property); + } + + if (prop === null) { + throw new Error(`Property ${property} not found in ${item}`); + } + + if (item[prop] instanceof Function || typeof item[prop] === 'function') { + return item[prop](); + } + return item[prop]; +} + +function defprotocol(spec) { + return new Protocol(spec); +} + +function defimpl(protocol, type, impl) { + protocol.implementation(type, impl); +} + +function build_namespace(ns, ns_string) { + let parts = ns_string.split('.'); + const root = ns; + let parent = ns; + + if (parts[0] === 'Elixir') { + parts = parts.slice(1); + } + + for (const part of parts) { + if (typeof parent[part] === 'undefined') { + parent[part] = {}; + } + + parent = parent[part]; + } + + root.__table__ = ns.__table__ || {}; + root.__table__[Symbol.for(ns_string)] = parent; + + return parent; +} + +function map_to_object(map) { + const object = {}; + + for (const [key, value] of map.entries()) { + if (value instanceof Map) { + object[key] = map_to_object(value); + } else { + object[key] = value; + } + } + + return object; +} + +class Recurse { + constructor(func) { + this.func = func; + } +} + +function trampoline$1(f) { + let currentValue = f; + + while (currentValue && currentValue instanceof Recurse) { + currentValue = currentValue.func(); + } + + return currentValue; +} + +function split_at(value, position) { + if (position < 0) { + const newPosition = value.length + position; + if (newPosition < 0) { + return new Core.Tuple('', value); + } + + return split_at(value, newPosition); + } + + let first = ''; + let second = ''; + let index = 0; + + for (const character of value) { + if (index < position) { + first = first + character; + } else { + second = second + character; + } + + index = index + 1; + } + + return new Core.Tuple(first, second); +} + +var Functions = { + call_property, + defprotocol, + defimpl, + build_namespace, + map_to_object, + trampoline: trampoline$1, + Recurse, + split_at +}; + +function _case(condition, clauses) { + return Core.Patterns.defmatchAsync(...clauses)(condition); +} + +function cond(...clauses) { + for (const clause of clauses) { + if (clause[0]) { + return clause[1](); + } + } + + throw new Error(); +} + +function _for(expression, generators, collectable_protocol, into = []) { + let [result, fun] = collectable_protocol.into(into); + + const generatedValues = run_list_generators(generators.pop()(), generators); + + for (const value of generatedValues) { + if (expression.guard.apply(this, value)) { + result = fun(result, new Core.Tuple(Symbol.for('cont'), expression.fn.apply(this, value))); + } + } + + return fun(result, Symbol.for('done')); +} + +function run_list_generators(generator, generators) { + if (generators.length == 0) { + return generator.map(x => { + if (Array.isArray(x)) { + return x; + } + return [x]; + }); + } + const list = generators.pop(); + + const next_gen = []; + for (const j of list()) { + for (const i of generator) { + next_gen.push([j].concat(i)); + } + } + + return run_list_generators(next_gen, generators); +} + +function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { + let result = null; + + try { + result = do_fun(); + } catch (e) { + let ex_result = null; + + if (rescue_function) { + try { + ex_result = rescue_function(e); + return ex_result; + } catch (ex) { + if (ex instanceof Core.Patterns.MatchError) { + throw ex; + } + } + } + + if (catch_fun) { + try { + ex_result = catch_fun(e); + return ex_result; + } catch (ex) { + if (ex instanceof Core.Patterns.MatchError) { + throw ex; + } + } + } + + throw e; + } finally { + if (after_function) { + after_function(); + } + } + + if (else_function) { + try { + return else_function(result); + } catch (ex) { + if (ex instanceof Core.Patterns.MatchError) { + throw new Error('No Match Found in Else'); + } + + throw ex; + } + } else { + return result; + } +} + +function _with(...args) { + let argsToPass = []; + let successFunction = null; + let elseFunction = null; + + if (typeof args[args.length - 2] === 'function') { + [successFunction, elseFunction] = args.splice(-2); + } else { + successFunction = args.pop(); + } + + for (let i = 0; i < args.length; i++) { + const [pattern, func] = args[i]; + + const result = func(...argsToPass); + + const patternResult = Core.Patterns.match_or_default(pattern, result); + + if (patternResult == null) { + if (elseFunction) { + return elseFunction.call(null, result); + } + return result; + } + + argsToPass = argsToPass.concat(patternResult); + } + + return successFunction(...argsToPass); +} + +function receive(clauses, after) { + console.warn('Receive not supported'); +} + +var SpecialForms = { + _case, + cond, + _for, + _try, + _with, + receive +}; + +// http://erlang.org/doc/man/lists.html +function reverse(list) { + return [...list].reverse(); +} + +function foreach(fun, list) { + list.forEach(x => fun(x)); + + return Symbol.for('ok'); +} + +function duplicate(n, elem) { + const list = []; + + while (list.length < n) { + list.push(elem); + } + + return list; +} + +function flatten(deepList, tail = []) { + const val = deepList.reduce((acc, value) => { + if (Array.isArray(value)) { + return acc.concat(flatten(value)); + } + + return acc.concat(value); + }, []); + + return val.concat(tail); +} + +function foldl(fun, acc0, list) { + return list.reduce((acc, value) => { + return fun(value, acc); + }, acc0); +} + +function foldr(fun, acc0, list) { + return foldl(fun, acc0, reverse(list)); +} + +function keyfind(key, n, tupleList) { + for (const tuple of tupleList) { + if (tuple.get(n - 1) === key) { + return tuple; + } + } + + return false; +} + +function keymember(key, n, tupleList) { + if (keyfind(key, n, tupleList) === false) { + return false; + } + + return true; +} + +function keyreplace(key, n, tupleList, newTuple) { + const newTupleList = [...tupleList]; + + for (let index = 0; index < newTupleList.length; index++) { + if (newTupleList[index].get(n - 1) === key) { + newTupleList[index] = newTuple; + return newTupleList; + } + } + + return newTupleList; +} + +function keysort(n, tupleList) { + const newTupleList = [...tupleList]; + + return newTupleList.sort((a, b) => { + if (a.get(n - 1) < b.get(n - 1)) { + return -1; + } else if (a.get(n - 1) > b.get(n - 1)) { + return 1; + } + + return 0; + }); +} + +function keystore(key, n, tupleList, newTuple) { + const newTupleList = [...tupleList]; + + for (let index = 0; index < newTupleList.length; index++) { + if (newTupleList[index].get(n - 1) === key) { + newTupleList[index] = newTuple; + return newTupleList; + } + } + + return newTupleList.concat(newTuple); +} + +function keydelete(key, n, tupleList) { + const newTupleList = []; + let deleted = false; + + for (let index = 0; index < tupleList.length; index++) { + if (deleted === false && tupleList[index].get(n - 1) === key) { + deleted = true; + } else { + newTupleList.push(tupleList[index]); + } + } + + return newTupleList; +} + +function keytake(key, n, tupleList) { + const result = keyfind(key, n, tupleList); + + if (result !== false) { + return new ErlangTypes$1.Tuple(result.get(n - 1), result, keydelete(key, n, tupleList)); + } + + return false; +} + +function mapfoldl(fun, acc0, list1) { + const listResult = []; + let accResult = acc0; + + for (const item of list1) { + const tuple = fun(item, accResult); + listResult.push(tuple.get(0)); + accResult = tuple.get(1); + } + + return new ErlangTypes$1.Tuple(listResult, accResult); +} + +function concat(things) { + return things.map(v => v.toString()).join(); +} + +function map(fun, list) { + return list.map(value => fun(value)); +} + +function filter(pred, list1) { + return list1.filter(x => pred(x)); +} + +function filtermap(fun, list1) { + const list2 = []; + + for (const item of list1) { + const value = fun(item); + + if (value === true) { + list2.push(item); + } else if (value instanceof ErlangTypes$1.Tuple && value.get(0) === true) { + list2.push(value.get(1)); + } + } + + return list2; +} + +function member(elem, list) { + for (const item of list) { + if (item === elem) { + return true; + } + } + + return false; +} + +function all(pred, list) { + for (const item of list) { + if (pred(item) === false) { + return false; + } + } + + return true; +} + +function any(pred, list) { + for (const item of list) { + if (pred(item) === true) { + return true; + } + } + + return false; +} + +function splitwith(pred, list) { + let switchToList2 = false; + const list1 = []; + const list2 = []; + + for (const item of list) { + if (switchToList2 === true) { + list2.push(item); + } else if (pred(item) === true) { + list1.push(item); + } else { + switchToList2 = true; + list2.push(item); + } + } + + return new ErlangTypes$1.Tuple(list1, list2); +} + +function sort(...args) { + if (args.length === 1) { + const list2 = [...args[0]]; + return list2.sort(); + } + + const fun = args[0]; + const list2 = [...args[1]]; + + return list2.sort((a, b) => { + const result = fun(a, b); + + if (result === true) { + return -1; + } + + return 1; + }); +} + +var lists = { + reverse, + foreach, + duplicate, + flatten, + foldl, + foldr, + keydelete, + keyfind, + keymember, + keyreplace, + keysort, + keystore, + keytake, + mapfoldl, + concat, + map, + filter, + filtermap, + member, + all, + any, + splitwith, + sort +}; + +// http://erlang.org/doc/man/erlang.html +const selfPID = new ErlangTypes$1.PID(); + +function atom_to_binary(atom, encoding = Symbol.for('utf8')) { + if (encoding !== Symbol.for('utf8')) { + throw new Error(`unsupported encoding ${encoding}`); + } + + if (atom === null) { + return 'nil'; + } else if (is_boolean$1(atom)) { + return atom.toString(); + } else if (atom.__MODULE__) { + return Symbol.keyFor(atom.__MODULE__); + } + + return Symbol.keyFor(atom); +} + +function atom_to_list(atom) { + return atom_to_binary(atom); +} + +function binary_to_atom(binary, encoding = Symbol.for('utf8')) { + if (encoding !== Symbol.for('utf8')) { + throw new Error(`unsupported encoding ${encoding}`); + } + + if (binary === 'nil') { + return null; + } else if (binary === 'true') { + return true; + } else if (binary === 'false') { + return false; + } + + return Symbol.for(binary); +} + +function binary_to_existing_atom(binary, encoding = Symbol.for('utf8')) { + return binary_to_atom(binary, encoding); +} + +function list_concatenation(list1, list2) { + return list1.concat(list2); +} + +function list_subtraction(list1, list2) { + const list = [...list1]; + + for (const item of list2) { + const index = list.indexOf(item); + + if (index > -1) { + list.splice(index, 1); + } + } + + return list; +} + +function div(left, right) { + return left / right; +} + +function not(x) { + return !x; +} + +function rem(left, right) { + return left % right; +} + +function band(left, right) { + return left & right; +} + +function bor(left, right) { + return left | right; +} + +function bnot(x) { + return ~x; +} + +function bsl(left, right) { + return left << right; +} + +function bsr(left, right) { + return left >> right; +} + +function bxor(left, right) { + return left ^ right; +} + +function is_atom(value) { + if (value === null) { + return true; + } else if (is_boolean$1(value)) { + return true; + } + + return typeof value === 'symbol' || value instanceof Symbol || value.__MODULE__ != null; +} + +function is_bitstring$1(value) { + return value instanceof ErlangTypes$1.BitString; +} + +function is_boolean$1(value) { + return typeof value === 'boolean' || value instanceof Boolean; +} + +function is_number$1(value) { + return typeof value === 'number' || value instanceof Number; +} + +function is_float(value) { + return is_number$1(value) && !Number.isInteger(value); +} + +function is_function$1(value) { + return typeof value === 'function' || value instanceof Function; +} + +function is_integer(value) { + return Number.isInteger(value); +} + +function is_list(value) { + return Array.isArray(value); +} + +function is_map$1(value) { + return value instanceof Map; +} + +function is_pid(value) { + return value instanceof ErlangTypes$1.PID; +} + +function is_port() { + return false; +} + +function is_reference(value) { + return value instanceof ErlangTypes$1.Reference; +} + +function is_tuple(value) { + return value instanceof ErlangTypes$1.Tuple; +} + +function is_binary(value) { + return typeof value === 'string' || value instanceof String; +} + +function element(n, tuple) { + return tuple.get(n - 1); +} + +function setelement(index, tuple1, value) { + const tupleData = [...tuple1.values]; + + tupleData[index - 1] = value; + + return new ErlangTypes$1.Tuple(...tupleData); +} + +function make_tuple(arity, initialValue) { + const list = []; + + for (let i = 0; i < arity; i++) { + list.push(initialValue); + } + + return new ErlangTypes$1.Tuple(...list); +} + +function insert_element(index, tuple, term) { + const list = [...tuple.values]; + list.splice(index - 1, 0, term); + + return new ErlangTypes$1.Tuple(...list); +} + +function append_element(tuple, term) { + const list = [...tuple.values]; + list.push(term); + + return new ErlangTypes$1.Tuple(...list); +} + +function delete_element(index, tuple) { + const list = [...tuple.values]; + list.splice(index - 1, 1); + + return new ErlangTypes$1.Tuple(...list); +} + +function tuple_to_list(tuple) { + const list = [...tuple.values]; + return list; +} + +function abs(number) { + return Math.abs(number); +} + +function apply(...args) { + if (args.length === 2) { + return args[0].apply(this, ...args[1]); + } + + return args[0][atom_to_binary(args[1])].apply(this, ...args[2]); +} + +function binary_part(binary, start, _length) { + return binary.substring(start, start + _length); +} + +function bit_size(bitstring) { + return bitstring.bit_size; +} + +function byte_size(bitstring) { + return bitstring.byte_size; +} + +function hd(list) { + return list[0]; +} + +function length(list) { + return list.length; +} + +function make_ref() { + return new ErlangTypes$1.Reference(); +} + +function map_size(map) { + return map.size; +} + +function max(first, second) { + return Math.max(first, second); +} + +function min(first, second) { + return Math.min(first, second); +} + +function round(number) { + return Math.round(number); +} + +function tl(list) { + return list.slice(1); +} + +function trunc(number) { + return Math.trunc(number); +} + +function tuple_size(tuple) { + return tuple.length; +} + +function binary_to_float(str) { + return parseFloat(str); +} + +function binary_to_integer(str, base = 10) { + return parseInt(str, base); +} + +function process_info(pid, item) { + if (item) { + if (item === Symbol.for('current_stacktrace')) { + return new ErlangTypes$1.Tuple(item, []); + } + + return new ErlangTypes$1.Tuple(item, null); + } + + return []; +} + +function list_to_binary(iolist) { + const iolistFlattened = lists.flatten(iolist); + + const value = iolistFlattened.reduce((acc, current) => { + if (current === null) { + return acc; + } else if (is_integer(current)) { + return acc + String.fromCodePoint(current); + } else if (is_bitstring$1(current)) { + return acc + String.fromCodePoint(...current.value); + } + + return acc + current; + }, ''); + + return value; +} + +function iolist_to_binary(ioListOrBinary) { + if (ioListOrBinary === null) { + return ''; + } + + if (is_binary(ioListOrBinary)) { + return ioListOrBinary; + } + + if (is_bitstring$1(ioListOrBinary)) { + return String.fromCodePoint(...ioListOrBinary.value); + } + + if (is_number$1(ioListOrBinary)) { + return String.fromCodePoint(ioListOrBinary); + } + + const iolistFlattened = lists.flatten(ioListOrBinary); + + const value = iolistFlattened.reduce((acc, current) => { + if (current === null) { + return acc; + } else if (is_integer(current)) { + return acc + String.fromCodePoint(current); + } else if (is_bitstring$1(current)) { + return acc + String.fromCodePoint(...current.value); + } + + return acc + iolist_to_binary(current); + }, ''); + + return value; +} + +function io_size(ioListOrBinary) { + return iolist_to_binary(ioListOrBinary).length; +} + +function integer_to_binary(integer, base = 10) { + return integer.toString(base); +} + +function node() { + return Symbol.for('nonode@nohost'); +} + +function self$1() { + return selfPID; +} + +function _throw(term) { + throw term; +} + +function error(reason) { + throw new ErlangTypes$1.Tuple(reason, []); +} + +function exit(...args) { + if (args.length === 2) { + throw args[1]; + } else { + throw args[0]; + } +} + +function raise(_class, reason) { + if (_class === Symbol.for('throw')) { + _throw(reason); + } else if (_class === Symbol.for('error')) { + error(reason); + } else { + exit(reason); + } +} + +var erlang = { + atom_to_binary, + binary_to_atom, + binary_to_existing_atom, + list_concatenation, + list_subtraction, + div, + not, + rem, + band, + bor, + bsl, + bsr, + bxor, + bnot, + is_bitstring: is_bitstring$1, + is_boolean: is_boolean$1, + is_float, + is_function: is_function$1, + is_integer, + is_list, + is_map: is_map$1, + is_number: is_number$1, + is_pid, + is_port, + is_reference, + is_tuple, + is_atom, + is_binary, + element, + setelement, + make_tuple, + insert_element, + append_element, + delete_element, + tuple_to_list, + abs, + apply, + binary_part, + bit_size, + byte_size, + hd, + length, + make_ref, + map_size, + max, + min, + round, + tl, + trunc, + tuple_size, + binary_to_float, + binary_to_integer, + process_info, + iolist_to_binary, + io_size, + integer_to_binary, + atom_to_list, + node, + self: self$1, + throw: _throw, + error, + exit, + raise, + list_to_binary +}; + +// http://erlang.org/doc/man/maps.html +const OK = Symbol.for('ok'); +const ERROR = Symbol.for('error'); +const BADMAP = Symbol.for('badmap'); +const BADKEY = Symbol.for('badkey'); + +function find(key, map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map); + } + + const value = map.get(key); + + if (typeof value !== 'undefined') { + return new ErlangTypes$1.Tuple(OK, value); + } + + return ERROR; +} + +function fold(fun, init, map) { + let acc = init; + + for (const [key, value] of map.entries()) { + acc = fun(key, value, acc); + } + + return acc; +} + +function remove(key, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map1); + } + + const map2 = new Map(map1); + + map2.delete(key); + + return map2; +} + +function to_list(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map); + } + + const list = []; + + for (const [key, value] of map.entries()) { + list.push(new ErlangTypes$1.Tuple(key, value)); + } + + return list; +} + +function from_list(list) { + return list.reduce((acc, item) => { + const [key, value] = item; + acc.set(key, value); + + return acc; + }, new Map()); +} + +function keys(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map); + } + + return Array.from(map.keys()); +} + +function values$1(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map); + } + + return Array.from(map.values()); +} + +function is_key(key, map) { + return map.has(key); +} + +function put(key, value, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map1); + } + + const map2 = new Map(map1); + map2.set(key, value); + + return map2; +} + +function merge(map1, map2) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map1); + } + + if (erlang.is_map(map2) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map2); + } + + return new Map([...map1, ...map2]); +} + +function update(key, value, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map1); + } + + if (is_key(key, map1) === false) { + return new ErlangTypes$1.Tuple(BADKEY, key); + } + + return new Map([...map1, [key, value]]); +} + +function get(...args) { + const key = args[0]; + const map = args[1]; + + if (erlang.is_map(map) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map); + } + + if (is_key(key)) { + return map.get(key); + } + + if (args.length === 3) { + return args[2]; + } + + return new ErlangTypes$1.Tuple(BADKEY, key); +} + +function take(key, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes$1.Tuple(BADMAP, map1); + } + + if (!is_key(key)) { + return ERROR; + } + + const value = map1.get(key); + const map2 = new Map(map1); + map2.delete(key); + + return new ErlangTypes$1.Tuple(value, map2); +} + +var maps = { + find, + fold, + remove, + to_list, + from_list, + keys, + values: values$1, + is_key, + put, + merge, + update, + get, + take +}; + +function warn(message) { + const messageString = message.join(''); + console.warn(`warning: ${messageString}`); + + return Symbol.for('ok'); +} + +var elixir_errors = { + warn +}; + +const MODULE = Symbol.for('elixir_config'); +const ets = new Map(); + +function _new(opts) { + ets.set(MODULE, new Map()); + ets.get(MODULE).set(MODULE, opts); + return MODULE; +} + +function _delete(module) { + ets.delete(module); + return true; +} + +function put$1(key, value) { + ets.get(MODULE).set(key, value); + return Symbol.for('ok'); +} + +function get$1(key) { + return ets.get(MODULE).get(key); +} + +function update$1(key, fun) { + const value = fun(ets.get(MODULE).get(key)); + put$1(key, value); + return value; +} + +function get_and_put(key, value) { + const oldValue = get$1(key); + put$1(key, value); + return oldValue; +} + +var elixir_config = { + new: _new, + delete: _delete, + put: put$1, + get: get$1, + update: update$1, + get_and_put +}; + +function put_chars(ioDevice, charData) { + const dataToWrite = erlang.iolist_to_binary(charData); + + if (ioDevice === Symbol.for('stderr')) { + console.error(dataToWrite); + } else { + console.log(dataToWrite); + } + + return Symbol.for('ok'); +} + +var io = { + put_chars +}; + +function copy(subject, n = 1) { + return subject.repeat(n); +} + +function list_to_bin(bytelist) { + return erlang.list_to_binary(bytelist); +} + +var binary = { + copy, + list_to_bin +}; + +function characters_to_list(characters, inEncoding = Symbol.for('unicode')) { + let values = characters; + + if (Array.isArray(characters)) { + values = lists.flatten(characters); + } + + if (erlang.is_binary(values)) { + return values.split('').map(c => c.codePointAt(0)); + } + + return values.reduce((acc, c) => { + if (erlang.is_integer(c)) { + return acc.concat(c); + } + + return acc.concat(characters_to_list(c, inEncoding)); + }, []); +} + +function characters_to_binary(characters) { + const values = characters_to_list(characters); + + return String.fromCodePoint(...values); +} + +var unicode = { + characters_to_list, + characters_to_binary +}; + +function get_key(key) { + let real_key = key; + + if (__elixirscript_names__.has(key)) { + real_key = __elixirscript_names__.get(key); + } + + if (__elixirscript_store__.has(real_key)) { + return real_key; + } + + throw new Error(`Key ${real_key} not found`); +} + +function create(value, name = null) { + const key = new Core.PID(); + + if (name !== null) { + __elixirscript_names__.set(name, key); + } + + return __elixirscript_store__.set(key, value); +} + +function update$2(key, value) { + const real_key = get_key(key); + return __elixirscript_store__.set(real_key, value); +} + +function read(key) { + const real_key = get_key(key); + return __elixirscript_store__.get(real_key); +} + +function remove$1(key) { + const real_key = get_key(key); + return __elixirscript_store__.delete(real_key); +} + +var Store = { + create, + update: update$2, + read, + remove: remove$1 +}; + +class Integer {} +class Float {} + +function get_global() { + if (typeof self !== 'undefined') { + return self; + } else if (typeof window !== 'undefined') { + return window; + } else if (typeof global !== 'undefined') { + return global; + } + + console.warn('No global state found'); + return null; +} + +const globalState = get_global(); + +globalState.__elixirscript_store__ = new Map(); +globalState.__elixirscript_names__ = new Map(); + +var Core = { + Tuple: ErlangTypes$1.Tuple, + PID: ErlangTypes$1.PID, + BitString: ErlangTypes$1.BitString, + Patterns, + Integer, + Float, + Functions, + SpecialForms, + Store, + global: globalState, + erlang, + maps, + lists, + elixir_errors, + io, + binary, + unicode, + elixir_config +}; + +var elixir = { + Core +}; + +return elixir; + +}()); diff --git a/rollup.config.js b/rollup.config.js index 167aff26..100bc033 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -9,11 +9,11 @@ export default { nodeResolve({ jsnext: true }), babel({ babelrc: false - }), - minify({ - keepFnName: true, - keepClassName: true }) + //minify({ + // keepFnName: true, + // keepClassName: true + //}) ], targets: [{ dest: 'priv/build/iife/ElixirScript.Core.js', format: 'iife' }] }; diff --git a/src/javascript/lib/core/special_forms.js b/src/javascript/lib/core/special_forms.js index fe00aa6d..a17d9197 100644 --- a/src/javascript/lib/core/special_forms.js +++ b/src/javascript/lib/core/special_forms.js @@ -1,7 +1,7 @@ import Core from '../core'; function _case(condition, clauses) { - return Core.Patterns.defmatch(...clauses)(condition); + return Core.Patterns.defmatchAsync(...clauses)(condition); } function cond(...clauses) { diff --git a/test/app/spec/main.spec.js b/test/app/spec/main.spec.js index d5dabf8e..06d0ba8d 100644 --- a/test/app/spec/main.spec.js +++ b/test/app/spec/main.spec.js @@ -3,10 +3,10 @@ import Elixir from '../build/elixirscript.build.js'; const sinon = require('sinon'); -test('Elixir.start:calls the modules start function', t => { +test('Elixir.start:calls the modules start function', async t => { const callback = sinon.spy(); - Elixir.start(Elixir.Main, [callback]); + await Elixir.start(Elixir.Main, [callback]); t.true(callback.called); }); diff --git a/test/support/main.ex b/test/support/main.ex index a2260e63..b8159547 100644 --- a/test/support/main.ex +++ b/test/support/main.ex @@ -1,7 +1,13 @@ +defmodule User do + defstruct name: "John", age: 27 +end + defmodule Main do def start(:normal, [callback]) do callback.("started") - Enum.map(1..5, fn(x) -> x * 2 end) + a = %User{} + #:console.log(a.name) + #:console.log(a.age) end end diff --git a/yarn.lock b/yarn.lock index 94483966..88f8de3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3712,9 +3712,8 @@ table@^4.0.1: slice-ansi "0.0.4" string-width "^2.0.0" -tailored@^2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/tailored/-/tailored-2.6.4.tgz#c81bdfe8b50c35298ed87c684d493467a87182c5" +"tailored@file:/Users/bryanjos/projects/basstype/tailored": + version "2.7.0" dependencies: erlang-types "^1.0.1" From 703cef3f46cb83829b7e142fa877e291d7eed53e Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Sat, 26 Aug 2017 15:35:30 -0500 Subject: [PATCH 2/6] More async fixes --- .tool-versions | 2 +- lib/elixir_script/passes/find_used_modules.ex | 2 + .../passes/translate/forms/for.ex | 10 +- .../translate/forms/pattern/patterns.ex | 2 +- package.json | 5 +- priv/build/iife/ElixirScript.Core.js | 596 ++++-------------- .../lib/core/erlang_compat/lists.js | 74 ++- src/javascript/lib/core/erlang_compat/maps.js | 4 +- src/javascript/lib/core/functions.js | 6 +- src/javascript/lib/core/protocol.js | 4 +- src/javascript/lib/core/special_forms.js | 36 +- test/support/main.ex | 8 - yarn.lock | 5 +- 13 files changed, 204 insertions(+), 550 deletions(-) diff --git a/.tool-versions b/.tool-versions index 4676ecd7..cb49a042 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ erlang 20.0 elixir 1.5.0-otp-20 -nodejs 8.2.1 +nodejs 8.3.0 diff --git a/lib/elixir_script/passes/find_used_modules.ex b/lib/elixir_script/passes/find_used_modules.ex index 1c470fc9..7c584775 100644 --- a/lib/elixir_script/passes/find_used_modules.ex +++ b/lib/elixir_script/passes/find_used_modules.ex @@ -165,6 +165,8 @@ defmodule ElixirScript.FindUsedModules do end defp walk({:for, _, generators}, state) do + walk(Collectable, state) + Enum.each(generators, fn {:<<>>, _, body} -> walk(body, state) diff --git a/lib/elixir_script/passes/translate/forms/for.ex b/lib/elixir_script/passes/translate/forms/for.ex index 3f57581e..f0a8942d 100644 --- a/lib/elixir_script/passes/translate/forms/for.ex +++ b/lib/elixir_script/passes/translate/forms/for.ex @@ -2,8 +2,7 @@ defmodule ElixirScript.Translate.Forms.For do @moduledoc false alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translate.Helpers - alias ElixirScript.Translate.{Form, Clause} + alias ElixirScript.Translate.{Form, Clause, Identifier, Helpers} alias ElixirScript.Translate.Forms.Pattern def compile({:for, _, generators}, state) do @@ -24,9 +23,10 @@ defmodule ElixirScript.Translate.Forms.For do [JS.array_expression(args.patterns), fun, filter] ) - collectable = JS.member_expression( - JS.identifier("Elixir"), - JS.identifier("Collectable") + members = ["Elixir", "Collectable", "__load"] + collectable = Helpers.call( + Identifier.make_namespace_members(members), + [JS.identifier("Elixir")] ) ast = Helpers.call( diff --git a/lib/elixir_script/passes/translate/forms/pattern/patterns.ex b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex index bf55821d..206297b4 100644 --- a/lib/elixir_script/passes/translate/forms/pattern/patterns.ex +++ b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex @@ -40,7 +40,7 @@ defmodule ElixirScript.Translate.Forms.Pattern.Patterns do ) def parameter() do - Helpers.call( + Helpers.call_sync( @parameter, [] ) diff --git a/package.json b/package.json index 4423a2a7..9f8a31fa 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "clean": "rm -rf priv/build", "test": "nyc ava src/javascript/tests", "build:test-app": "MIX_ENV=test mix elixirscript Main -o test/app/build/", - "test-app": "yarn build:test-app && NODE_ENV=test ava 'test/app/spec/**/*.spec.js'" + "test:test-app": "NODE_ENV=test ava 'test/app/spec/**/*.spec.js'", + "test-app": "yarn build && yarn build:test-app && yarn test:test-app" }, "repository": { "type": "git", @@ -23,7 +24,7 @@ "license": "MIT", "dependencies": { "erlang-types": "^1.0.1", - "tailored": "file:/Users/bryanjos/projects/basstype/tailored" + "tailored": "^2.7.1" }, "devDependencies": { "ava": "^0.21.0", diff --git a/priv/build/iife/ElixirScript.Core.js b/priv/build/iife/ElixirScript.Core.js index de543b31..0604c9bb 100644 --- a/priv/build/iife/ElixirScript.Core.js +++ b/priv/build/iife/ElixirScript.Core.js @@ -161,7 +161,7 @@ function is_array(value) { } function is_function(value) { - return Object.prototype.toString.call(value) == '[object Function]'; + return typeof value === 'function' || value instanceof Function; } function is_map(value) { @@ -917,6 +917,10 @@ function buildMatch(pattern) { return resolveWildcard(pattern); } + if (typeof pattern === 'function') { + return resolveFunction(pattern); + } + const type$$1 = pattern.constructor.prototype; const resolver = patternMap.get(type$$1); @@ -953,7 +957,6 @@ class MatchError extends Error { this.message = 'No match for: ' + arg; } - this.stack = new Error().stack; this.name = this.constructor.name; } } @@ -1315,405 +1318,6 @@ var Patterns = { defmatchAsync }; -class Tuple$2 { - constructor(...args) { - this.values = Object.freeze(args); - this.length = this.values.length; - } - - get(index) { - return this.values[index]; - } - - count() { - return this.values.length; - } - - [Symbol.iterator]() { - return this.values[Symbol.iterator](); - } - - toString() { - let i, - s = ''; - for (i = 0; i < this.values.length; i++) { - if (s !== '') { - s += ', '; - } - - const stringToAppend = this.values[i] ? this.values[i].toString() : ''; - - s += stringToAppend; - } - - return '{' + s + '}'; - } - - put_elem(index, elem) { - if (index === this.length) { - let new_values = this.values.concat([elem]); - return new Tuple$2(...new_values); - } - - let new_values = this.values.concat([]); - new_values.splice(index, 0, elem); - return new Tuple$2(...new_values); - } - - remove_elem(index) { - let new_values = this.values.concat([]); - new_values.splice(index, 1); - return new Tuple$2(...new_values); - } -} - -let process_counter$1 = -1; - -class PID$2 { - constructor() { - process_counter$1 = process_counter$1 + 1; - this.id = process_counter$1; - } - - toString() { - return 'PID#<0.' + this.id + '.0>'; - } -} - -let ref_counter$1 = -1; - -class Reference$2 { - constructor() { - ref_counter$1 = ref_counter$1 + 1; - this.id = ref_counter$1; - this.ref = Symbol(); - } - - toString() { - return 'Ref#<0.0.0.' + this.id + '>'; - } -} - -class BitString$3 { - constructor(...args) { - this.value = Object.freeze(this.process(args)); - this.length = this.value.length; - this.bit_size = this.length * 8; - this.byte_size = this.length; - } - - get(index) { - return this.value[index]; - } - - count() { - return this.value.length; - } - - slice(start, end = null) { - let s = this.value.slice(start, end); - let ms = s.map(elem => BitString$3.integer(elem)); - return new BitString$3(...ms); - } - - [Symbol.iterator]() { - return this.value[Symbol.iterator](); - } - - toString() { - var i, - s = ''; - for (i = 0; i < this.count(); i++) { - if (s !== '') { - s += ', '; - } - s += this.get(i).toString(); - } - - return '<<' + s + '>>'; - } - - process(bitStringParts) { - let processed_values = []; - - var i; - for (i = 0; i < bitStringParts.length; i++) { - let processed_value = this['process_' + bitStringParts[i].type](bitStringParts[i]); - - for (let attr of bitStringParts[i].attributes) { - processed_value = this['process_' + attr](processed_value); - } - - processed_values = processed_values.concat(processed_value); - } - - return processed_values; - } - - process_integer(value) { - return value.value; - } - - process_float(value) { - if (value.size === 64) { - return BitString$3.float64ToBytes(value.value); - } else if (value.size === 32) { - return BitString$3.float32ToBytes(value.value); - } - - throw new Error('Invalid size for float'); - } - - process_bitstring(value) { - return value.value.value; - } - - process_binary(value) { - return BitString$3.toUTF8Array(value.value); - } - - process_utf8(value) { - return BitString$3.toUTF8Array(value.value); - } - - process_utf16(value) { - return BitString$3.toUTF16Array(value.value); - } - - process_utf32(value) { - return BitString$3.toUTF32Array(value.value); - } - - process_signed(value) { - return new Uint8Array([value])[0]; - } - - process_unsigned(value) { - return value; - } - - process_native(value) { - return value; - } - - process_big(value) { - return value; - } - - process_little(value) { - return value.reverse(); - } - - process_size(value) { - return value; - } - - process_unit(value) { - return value; - } - - static integer(value) { - return BitString$3.wrap(value, { type: 'integer', unit: 1, size: 8 }); - } - - static float(value) { - return BitString$3.wrap(value, { type: 'float', unit: 1, size: 64 }); - } - - static bitstring(value) { - return BitString$3.wrap(value, { - type: 'bitstring', - unit: 1, - size: value.bit_size - }); - } - - static bits(value) { - return BitString$3.bitstring(value); - } - - static binary(value) { - return BitString$3.wrap(value, { - type: 'binary', - unit: 8, - size: value.length - }); - } - - static bytes(value) { - return BitString$3.binary(value); - } - - static utf8(value) { - return BitString$3.wrap(value, { type: 'utf8', unit: 1, size: value.length }); - } - - static utf16(value) { - return BitString$3.wrap(value, { - type: 'utf16', - unit: 1, - size: value.length * 2 - }); - } - - static utf32(value) { - return BitString$3.wrap(value, { - type: 'utf32', - unit: 1, - size: value.length * 4 - }); - } - - static signed(value) { - return BitString$3.wrap(value, {}, 'signed'); - } - - static unsigned(value) { - return BitString$3.wrap(value, {}, 'unsigned'); - } - - static native(value) { - return BitString$3.wrap(value, {}, 'native'); - } - - static big(value) { - return BitString$3.wrap(value, {}, 'big'); - } - - static little(value) { - return BitString$3.wrap(value, {}, 'little'); - } - - static size(value, count) { - return BitString$3.wrap(value, { size: count }); - } - - static unit(value, count) { - return BitString$3.wrap(value, { unit: count }); - } - - static wrap(value, opt, new_attribute = null) { - let the_value = value; - - if (!(value instanceof Object)) { - the_value = { value: value, attributes: [] }; - } - - the_value = Object.assign(the_value, opt); - - if (new_attribute) { - the_value.attributes.push(new_attribute); - } - - return the_value; - } - - static toUTF8Array(str) { - var utf8 = []; - for (var i = 0; i < str.length; i++) { - var charcode = str.charCodeAt(i); - if (charcode < 0x80) { - utf8.push(charcode); - } else if (charcode < 0x800) { - utf8.push(0xc0 | charcode >> 6, 0x80 | charcode & 0x3f); - } else if (charcode < 0xd800 || charcode >= 0xe000) { - utf8.push(0xe0 | charcode >> 12, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); - } else { - // surrogate pair - i++; - // UTF-16 encodes 0x10000-0x10FFFF by - // subtracting 0x10000 and splitting the - // 20 bits of 0x0-0xFFFFF into two halves - charcode = 0x10000 + ((charcode & 0x3ff) << 10 | str.charCodeAt(i) & 0x3ff); - utf8.push(0xf0 | charcode >> 18, 0x80 | charcode >> 12 & 0x3f, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f); - } - } - return utf8; - } - - static toUTF16Array(str) { - var utf16 = []; - for (var i = 0; i < str.length; i++) { - var codePoint = str.codePointAt(i); - - if (codePoint <= 255) { - utf16.push(0); - utf16.push(codePoint); - } else { - utf16.push(codePoint >> 8 & 0xff); - utf16.push(codePoint & 0xff); - } - } - return utf16; - } - - static toUTF32Array(str) { - var utf32 = []; - for (var i = 0; i < str.length; i++) { - var codePoint = str.codePointAt(i); - - if (codePoint <= 255) { - utf32.push(0); - utf32.push(0); - utf32.push(0); - utf32.push(codePoint); - } else { - utf32.push(0); - utf32.push(0); - utf32.push(codePoint >> 8 & 0xff); - utf32.push(codePoint & 0xff); - } - } - return utf32; - } - - //http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits - static float32ToBytes(f) { - var bytes = []; - - var buf = new ArrayBuffer(4); - new Float32Array(buf)[0] = f; - - let intVersion = new Uint32Array(buf)[0]; - - bytes.push(intVersion >> 24 & 0xff); - bytes.push(intVersion >> 16 & 0xff); - bytes.push(intVersion >> 8 & 0xff); - bytes.push(intVersion & 0xff); - - return bytes; - } - - static float64ToBytes(f) { - var bytes = []; - - var buf = new ArrayBuffer(8); - new Float64Array(buf)[0] = f; - - var intVersion1 = new Uint32Array(buf)[0]; - var intVersion2 = new Uint32Array(buf)[1]; - - bytes.push(intVersion2 >> 24 & 0xff); - bytes.push(intVersion2 >> 16 & 0xff); - bytes.push(intVersion2 >> 8 & 0xff); - bytes.push(intVersion2 & 0xff); - - bytes.push(intVersion1 >> 24 & 0xff); - bytes.push(intVersion1 >> 16 & 0xff); - bytes.push(intVersion1 >> 8 & 0xff); - bytes.push(intVersion1 & 0xff); - - return bytes; - } -} - -var ErlangTypes$1 = { - Tuple: Tuple$2, - PID: PID$2, - Reference: Reference$2, - BitString: BitString$3 -}; - // https://github.com/airportyh/protomorphism class Protocol { constructor(spec) { @@ -1721,7 +1325,7 @@ class Protocol { this.fallback = null; function createFun(funName) { - return function (...args) { + return async function (...args) { const thing = args[0]; let fun = null; @@ -1742,7 +1346,7 @@ class Protocol { } if (fun != null) { - const retval = fun.apply(this, args); + const retval = await fun.apply(this, args); return retval; } @@ -1774,7 +1378,7 @@ class Protocol { } } -function call_property(item, property) { +async function call_property(item, property) { if (!property) { if (item instanceof Function || typeof item === 'function') { return item(); @@ -1877,11 +1481,11 @@ class Recurse { } } -function trampoline$1(f) { +async function trampoline$1(f) { let currentValue = f; while (currentValue && currentValue instanceof Recurse) { - currentValue = currentValue.func(); + currentValue = await currentValue.func(); } return currentValue; @@ -1925,11 +1529,11 @@ var Functions = { split_at }; -function _case(condition, clauses) { +async function _case(condition, clauses) { return Core.Patterns.defmatchAsync(...clauses)(condition); } -function cond(...clauses) { +async function cond(...clauses) { for (const clause of clauses) { if (clause[0]) { return clause[1](); @@ -1939,14 +1543,14 @@ function cond(...clauses) { throw new Error(); } -function _for(expression, generators, collectable_protocol, into = []) { +async function _for(expression, generators, collectable_protocol, into = []) { let [result, fun] = collectable_protocol.into(into); const generatedValues = run_list_generators(generators.pop()(), generators); for (const value of generatedValues) { - if (expression.guard.apply(this, value)) { - result = fun(result, new Core.Tuple(Symbol.for('cont'), expression.fn.apply(this, value))); + if (await expression.guard.apply(this, value)) { + result = await fun(result, new Core.Tuple(Symbol.for('cont'), (await expression.fn.apply(this, value)))); } } @@ -1954,7 +1558,7 @@ function _for(expression, generators, collectable_protocol, into = []) { } function run_list_generators(generator, generators) { - if (generators.length == 0) { + if (generators.length === 0) { return generator.map(x => { if (Array.isArray(x)) { return x; @@ -1974,17 +1578,17 @@ function run_list_generators(generator, generators) { return run_list_generators(next_gen, generators); } -function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { +async function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { let result = null; try { - result = do_fun(); + result = await do_fun(); } catch (e) { let ex_result = null; if (rescue_function) { try { - ex_result = rescue_function(e); + ex_result = await rescue_function(e); return ex_result; } catch (ex) { if (ex instanceof Core.Patterns.MatchError) { @@ -1995,7 +1599,7 @@ function _try(do_fun, rescue_function, catch_fun, else_function, after_function) if (catch_fun) { try { - ex_result = catch_fun(e); + ex_result = await catch_fun(e); return ex_result; } catch (ex) { if (ex instanceof Core.Patterns.MatchError) { @@ -2007,7 +1611,7 @@ function _try(do_fun, rescue_function, catch_fun, else_function, after_function) throw e; } finally { if (after_function) { - after_function(); + await after_function(); } } @@ -2026,7 +1630,7 @@ function _try(do_fun, rescue_function, catch_fun, else_function, after_function) } } -function _with(...args) { +async function _with(...args) { let argsToPass = []; let successFunction = null; let elseFunction = null; @@ -2040,9 +1644,9 @@ function _with(...args) { for (let i = 0; i < args.length; i++) { const [pattern, func] = args[i]; - const result = func(...argsToPass); + const result = await func(...argsToPass); - const patternResult = Core.Patterns.match_or_default(pattern, result); + const patternResult = await Core.Patterns.match_or_default_async(pattern, result); if (patternResult == null) { if (elseFunction) { @@ -2075,8 +1679,10 @@ function reverse(list) { return [...list].reverse(); } -function foreach(fun, list) { - list.forEach(x => fun(x)); +async function foreach(fun, list) { + for (const x of list) { + await fun(x); + } return Symbol.for('ok'); } @@ -2103,13 +1709,17 @@ function flatten(deepList, tail = []) { return val.concat(tail); } -function foldl(fun, acc0, list) { - return list.reduce((acc, value) => { - return fun(value, acc); - }, acc0); +async function foldl(fun, acc0, list) { + let acc = acc0; + + for (const value of list) { + acc = await fun(value, acc); + } + + return acc; } -function foldr(fun, acc0, list) { +async function foldr(fun, acc0, list) { return foldl(fun, acc0, reverse(list)); } @@ -2190,46 +1800,62 @@ function keytake(key, n, tupleList) { const result = keyfind(key, n, tupleList); if (result !== false) { - return new ErlangTypes$1.Tuple(result.get(n - 1), result, keydelete(key, n, tupleList)); + return new ErlangTypes.Tuple(result.get(n - 1), result, keydelete(key, n, tupleList)); } return false; } -function mapfoldl(fun, acc0, list1) { +async function mapfoldl(fun, acc0, list1) { const listResult = []; let accResult = acc0; for (const item of list1) { - const tuple = fun(item, accResult); + const tuple = await fun(item, accResult); listResult.push(tuple.get(0)); accResult = tuple.get(1); } - return new ErlangTypes$1.Tuple(listResult, accResult); + return new ErlangTypes.Tuple(listResult, accResult); } function concat(things) { return things.map(v => v.toString()).join(); } -function map(fun, list) { - return list.map(value => fun(value)); +async function map(fun, list) { + const reList = []; + + for (const value of list) { + const result = await fun(value); + reList.push(result); + } + + return reList; } -function filter(pred, list1) { - return list1.filter(x => pred(x)); +async function filter(pred, list1) { + const reList = []; + + for (const value of list1) { + const result = await pred(value); + if (result === true) { + reList.push(value); + } + } + + return reList; } -function filtermap(fun, list1) { +async function filtermap(fun, list1) { const list2 = []; for (const item of list1) { - const value = fun(item); + const value = await fun(item); if (value === true) { list2.push(item); - } else if (value instanceof ErlangTypes$1.Tuple && value.get(0) === true) { + } else if (value instanceof ErlangTypes.Tuple && value.get(0) === true) { list2.push(value.get(1)); } } @@ -2247,9 +1873,9 @@ function member(elem, list) { return false; } -function all(pred, list) { +async function all(pred, list) { for (const item of list) { - if (pred(item) === false) { + if ((await pred(item)) === false) { return false; } } @@ -2257,9 +1883,9 @@ function all(pred, list) { return true; } -function any(pred, list) { +async function any(pred, list) { for (const item of list) { - if (pred(item) === true) { + if ((await pred(item)) === true) { return true; } } @@ -2267,7 +1893,7 @@ function any(pred, list) { return false; } -function splitwith(pred, list) { +async function splitwith(pred, list) { let switchToList2 = false; const list1 = []; const list2 = []; @@ -2275,7 +1901,7 @@ function splitwith(pred, list) { for (const item of list) { if (switchToList2 === true) { list2.push(item); - } else if (pred(item) === true) { + } else if ((await pred(item)) === true) { list1.push(item); } else { switchToList2 = true; @@ -2283,10 +1909,10 @@ function splitwith(pred, list) { } } - return new ErlangTypes$1.Tuple(list1, list2); + return new ErlangTypes.Tuple(list1, list2); } -function sort(...args) { +async function sort(...args) { if (args.length === 1) { const list2 = [...args[0]]; return list2.sort(); @@ -2295,15 +1921,17 @@ function sort(...args) { const fun = args[0]; const list2 = [...args[1]]; - return list2.sort((a, b) => { - const result = fun(a, b); + const result = list2.sort(async (a, b) => { + const sortResult = await fun(a, b); - if (result === true) { + if (sortResult === true) { return -1; } return 1; }); + + return Promise.all(result); } var lists = { @@ -2333,7 +1961,7 @@ var lists = { }; // http://erlang.org/doc/man/erlang.html -const selfPID = new ErlangTypes$1.PID(); +const selfPID = new ErlangTypes.PID(); function atom_to_binary(atom, encoding = Symbol.for('utf8')) { if (encoding !== Symbol.for('utf8')) { @@ -2440,7 +2068,7 @@ function is_atom(value) { } function is_bitstring$1(value) { - return value instanceof ErlangTypes$1.BitString; + return value instanceof ErlangTypes.BitString; } function is_boolean$1(value) { @@ -2472,7 +2100,7 @@ function is_map$1(value) { } function is_pid(value) { - return value instanceof ErlangTypes$1.PID; + return value instanceof ErlangTypes.PID; } function is_port() { @@ -2480,11 +2108,11 @@ function is_port() { } function is_reference(value) { - return value instanceof ErlangTypes$1.Reference; + return value instanceof ErlangTypes.Reference; } function is_tuple(value) { - return value instanceof ErlangTypes$1.Tuple; + return value instanceof ErlangTypes.Tuple; } function is_binary(value) { @@ -2500,7 +2128,7 @@ function setelement(index, tuple1, value) { tupleData[index - 1] = value; - return new ErlangTypes$1.Tuple(...tupleData); + return new ErlangTypes.Tuple(...tupleData); } function make_tuple(arity, initialValue) { @@ -2510,28 +2138,28 @@ function make_tuple(arity, initialValue) { list.push(initialValue); } - return new ErlangTypes$1.Tuple(...list); + return new ErlangTypes.Tuple(...list); } function insert_element(index, tuple, term) { const list = [...tuple.values]; list.splice(index - 1, 0, term); - return new ErlangTypes$1.Tuple(...list); + return new ErlangTypes.Tuple(...list); } function append_element(tuple, term) { const list = [...tuple.values]; list.push(term); - return new ErlangTypes$1.Tuple(...list); + return new ErlangTypes.Tuple(...list); } function delete_element(index, tuple) { const list = [...tuple.values]; list.splice(index - 1, 1); - return new ErlangTypes$1.Tuple(...list); + return new ErlangTypes.Tuple(...list); } function tuple_to_list(tuple) { @@ -2572,7 +2200,7 @@ function length(list) { } function make_ref() { - return new ErlangTypes$1.Reference(); + return new ErlangTypes.Reference(); } function map_size(map) { @@ -2614,10 +2242,10 @@ function binary_to_integer(str, base = 10) { function process_info(pid, item) { if (item) { if (item === Symbol.for('current_stacktrace')) { - return new ErlangTypes$1.Tuple(item, []); + return new ErlangTypes.Tuple(item, []); } - return new ErlangTypes$1.Tuple(item, null); + return new ErlangTypes.Tuple(item, null); } return []; @@ -2696,7 +2324,7 @@ function _throw(term) { } function error(reason) { - throw new ErlangTypes$1.Tuple(reason, []); + throw new ErlangTypes.Tuple(reason, []); } function exit(...args) { @@ -2792,23 +2420,23 @@ const BADKEY = Symbol.for('badkey'); function find(key, map) { if (erlang.is_map(map) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map); + return new ErlangTypes.Tuple(BADMAP, map); } const value = map.get(key); if (typeof value !== 'undefined') { - return new ErlangTypes$1.Tuple(OK, value); + return new ErlangTypes.Tuple(OK, value); } return ERROR; } -function fold(fun, init, map) { +async function fold(fun, init, map) { let acc = init; for (const [key, value] of map.entries()) { - acc = fun(key, value, acc); + acc = await fun(key, value, acc); } return acc; @@ -2816,7 +2444,7 @@ function fold(fun, init, map) { function remove(key, map1) { if (erlang.is_map(map1) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map1); + return new ErlangTypes.Tuple(BADMAP, map1); } const map2 = new Map(map1); @@ -2828,13 +2456,13 @@ function remove(key, map1) { function to_list(map) { if (erlang.is_map(map) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map); + return new ErlangTypes.Tuple(BADMAP, map); } const list = []; for (const [key, value] of map.entries()) { - list.push(new ErlangTypes$1.Tuple(key, value)); + list.push(new ErlangTypes.Tuple(key, value)); } return list; @@ -2851,7 +2479,7 @@ function from_list(list) { function keys(map) { if (erlang.is_map(map) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map); + return new ErlangTypes.Tuple(BADMAP, map); } return Array.from(map.keys()); @@ -2859,7 +2487,7 @@ function keys(map) { function values$1(map) { if (erlang.is_map(map) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map); + return new ErlangTypes.Tuple(BADMAP, map); } return Array.from(map.values()); @@ -2871,7 +2499,7 @@ function is_key(key, map) { function put(key, value, map1) { if (erlang.is_map(map1) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map1); + return new ErlangTypes.Tuple(BADMAP, map1); } const map2 = new Map(map1); @@ -2882,11 +2510,11 @@ function put(key, value, map1) { function merge(map1, map2) { if (erlang.is_map(map1) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map1); + return new ErlangTypes.Tuple(BADMAP, map1); } if (erlang.is_map(map2) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map2); + return new ErlangTypes.Tuple(BADMAP, map2); } return new Map([...map1, ...map2]); @@ -2894,11 +2522,11 @@ function merge(map1, map2) { function update(key, value, map1) { if (erlang.is_map(map1) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map1); + return new ErlangTypes.Tuple(BADMAP, map1); } if (is_key(key, map1) === false) { - return new ErlangTypes$1.Tuple(BADKEY, key); + return new ErlangTypes.Tuple(BADKEY, key); } return new Map([...map1, [key, value]]); @@ -2909,7 +2537,7 @@ function get(...args) { const map = args[1]; if (erlang.is_map(map) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map); + return new ErlangTypes.Tuple(BADMAP, map); } if (is_key(key)) { @@ -2920,12 +2548,12 @@ function get(...args) { return args[2]; } - return new ErlangTypes$1.Tuple(BADKEY, key); + return new ErlangTypes.Tuple(BADKEY, key); } function take(key, map1) { if (erlang.is_map(map1) === false) { - return new ErlangTypes$1.Tuple(BADMAP, map1); + return new ErlangTypes.Tuple(BADMAP, map1); } if (!is_key(key)) { @@ -2936,7 +2564,7 @@ function take(key, map1) { const map2 = new Map(map1); map2.delete(key); - return new ErlangTypes$1.Tuple(value, map2); + return new ErlangTypes.Tuple(value, map2); } var maps = { @@ -3138,9 +2766,9 @@ globalState.__elixirscript_store__ = new Map(); globalState.__elixirscript_names__ = new Map(); var Core = { - Tuple: ErlangTypes$1.Tuple, - PID: ErlangTypes$1.PID, - BitString: ErlangTypes$1.BitString, + Tuple: ErlangTypes.Tuple, + PID: ErlangTypes.PID, + BitString: ErlangTypes.BitString, Patterns, Integer, Float, diff --git a/src/javascript/lib/core/erlang_compat/lists.js b/src/javascript/lib/core/erlang_compat/lists.js index 9e9daf43..36fdf438 100644 --- a/src/javascript/lib/core/erlang_compat/lists.js +++ b/src/javascript/lib/core/erlang_compat/lists.js @@ -5,8 +5,10 @@ function reverse(list) { return [...list].reverse(); } -function foreach(fun, list) { - list.forEach(x => fun(x)); +async function foreach(fun, list) { + for (const x of list) { + await fun(x); + } return Symbol.for('ok'); } @@ -33,13 +35,17 @@ function flatten(deepList, tail = []) { return val.concat(tail); } -function foldl(fun, acc0, list) { - return list.reduce((acc, value) => { - return fun(value, acc); - }, acc0); +async function foldl(fun, acc0, list) { + let acc = acc0; + + for (const value of list) { + acc = await fun(value, acc); + } + + return acc; } -function foldr(fun, acc0, list) { +async function foldr(fun, acc0, list) { return foldl(fun, acc0, reverse(list)); } @@ -130,12 +136,12 @@ function keytake(key, n, tupleList) { return false; } -function mapfoldl(fun, acc0, list1) { +async function mapfoldl(fun, acc0, list1) { const listResult = []; let accResult = acc0; for (const item of list1) { - const tuple = fun(item, accResult); + const tuple = await fun(item, accResult); listResult.push(tuple.get(0)); accResult = tuple.get(1); } @@ -147,19 +153,35 @@ function concat(things) { return things.map(v => v.toString()).join(); } -function map(fun, list) { - return list.map(value => fun(value)); +async function map(fun, list) { + const reList = []; + + for (const value of list) { + const result = await fun(value); + reList.push(result); + } + + return reList; } -function filter(pred, list1) { - return list1.filter(x => pred(x)); +async function filter(pred, list1) { + const reList = []; + + for (const value of list1) { + const result = await pred(value); + if (result === true) { + reList.push(value); + } + } + + return reList; } -function filtermap(fun, list1) { +async function filtermap(fun, list1) { const list2 = []; for (const item of list1) { - const value = fun(item); + const value = await fun(item); if (value === true) { list2.push(item); @@ -181,9 +203,9 @@ function member(elem, list) { return false; } -function all(pred, list) { +async function all(pred, list) { for (const item of list) { - if (pred(item) === false) { + if ((await pred(item)) === false) { return false; } } @@ -191,9 +213,9 @@ function all(pred, list) { return true; } -function any(pred, list) { +async function any(pred, list) { for (const item of list) { - if (pred(item) === true) { + if ((await pred(item)) === true) { return true; } } @@ -201,7 +223,7 @@ function any(pred, list) { return false; } -function splitwith(pred, list) { +async function splitwith(pred, list) { let switchToList2 = false; const list1 = []; const list2 = []; @@ -209,7 +231,7 @@ function splitwith(pred, list) { for (const item of list) { if (switchToList2 === true) { list2.push(item); - } else if (pred(item) === true) { + } else if ((await pred(item)) === true) { list1.push(item); } else { switchToList2 = true; @@ -220,7 +242,7 @@ function splitwith(pred, list) { return new ErlangTypes.Tuple(list1, list2); } -function sort(...args) { +async function sort(...args) { if (args.length === 1) { const list2 = [...args[0]]; return list2.sort(); @@ -229,15 +251,17 @@ function sort(...args) { const fun = args[0]; const list2 = [...args[1]]; - return list2.sort((a, b) => { - const result = fun(a, b); + const result = list2.sort(async (a, b) => { + const sortResult = await fun(a, b); - if (result === true) { + if (sortResult === true) { return -1; } return 1; }); + + return Promise.all(result); } export default { diff --git a/src/javascript/lib/core/erlang_compat/maps.js b/src/javascript/lib/core/erlang_compat/maps.js index 9f0686c3..7d7338c4 100644 --- a/src/javascript/lib/core/erlang_compat/maps.js +++ b/src/javascript/lib/core/erlang_compat/maps.js @@ -21,11 +21,11 @@ function find(key, map) { return ERROR; } -function fold(fun, init, map) { +async function fold(fun, init, map) { let acc = init; for (const [key, value] of map.entries()) { - acc = fun(key, value, acc); + acc = await fun(key, value, acc); } return acc; diff --git a/src/javascript/lib/core/functions.js b/src/javascript/lib/core/functions.js index 184bd7a2..8a9e01aa 100644 --- a/src/javascript/lib/core/functions.js +++ b/src/javascript/lib/core/functions.js @@ -1,7 +1,7 @@ import Protocol from './protocol'; import Core from '../core'; -function call_property(item, property) { +async function call_property(item, property) { if (!property) { if (item instanceof Function || typeof item === 'function') { return item(); @@ -112,11 +112,11 @@ class Recurse { } } -function trampoline(f) { +async function trampoline(f) { let currentValue = f; while (currentValue && currentValue instanceof Recurse) { - currentValue = currentValue.func(); + currentValue = await currentValue.func(); } return currentValue; diff --git a/src/javascript/lib/core/protocol.js b/src/javascript/lib/core/protocol.js index 1b508e29..604cdb44 100644 --- a/src/javascript/lib/core/protocol.js +++ b/src/javascript/lib/core/protocol.js @@ -7,7 +7,7 @@ class Protocol { this.fallback = null; function createFun(funName) { - return function(...args) { + return async function(...args) { const thing = args[0]; let fun = null; @@ -45,7 +45,7 @@ class Protocol { } if (fun != null) { - const retval = fun.apply(this, args); + const retval = await fun.apply(this, args); return retval; } diff --git a/src/javascript/lib/core/special_forms.js b/src/javascript/lib/core/special_forms.js index a17d9197..6cad5fd6 100644 --- a/src/javascript/lib/core/special_forms.js +++ b/src/javascript/lib/core/special_forms.js @@ -1,10 +1,10 @@ import Core from '../core'; -function _case(condition, clauses) { +async function _case(condition, clauses) { return Core.Patterns.defmatchAsync(...clauses)(condition); } -function cond(...clauses) { +async function cond(...clauses) { for (const clause of clauses) { if (clause[0]) { return clause[1](); @@ -14,16 +14,19 @@ function cond(...clauses) { throw new Error(); } -function _for(expression, generators, collectable_protocol, into = []) { +async function _for(expression, generators, collectable_protocol, into = []) { let [result, fun] = collectable_protocol.into(into); const generatedValues = run_list_generators(generators.pop()(), generators); for (const value of generatedValues) { - if (expression.guard.apply(this, value)) { - result = fun( + if (await expression.guard.apply(this, value)) { + result = await fun( result, - new Core.Tuple(Symbol.for('cont'), expression.fn.apply(this, value)) + new Core.Tuple( + Symbol.for('cont'), + await expression.fn.apply(this, value) + ) ); } } @@ -32,7 +35,7 @@ function _for(expression, generators, collectable_protocol, into = []) { } function run_list_generators(generator, generators) { - if (generators.length == 0) { + if (generators.length === 0) { return generator.map(x => { if (Array.isArray(x)) { return x; @@ -52,7 +55,7 @@ function run_list_generators(generator, generators) { return run_list_generators(next_gen, generators); } -function _try( +async function _try( do_fun, rescue_function, catch_fun, @@ -62,13 +65,13 @@ function _try( let result = null; try { - result = do_fun(); + result = await do_fun(); } catch (e) { let ex_result = null; if (rescue_function) { try { - ex_result = rescue_function(e); + ex_result = await rescue_function(e); return ex_result; } catch (ex) { if (ex instanceof Core.Patterns.MatchError) { @@ -79,7 +82,7 @@ function _try( if (catch_fun) { try { - ex_result = catch_fun(e); + ex_result = await catch_fun(e); return ex_result; } catch (ex) { if (ex instanceof Core.Patterns.MatchError) { @@ -91,7 +94,7 @@ function _try( throw e; } finally { if (after_function) { - after_function(); + await after_function(); } } @@ -110,7 +113,7 @@ function _try( } } -function _with(...args) { +async function _with(...args) { let argsToPass = []; let successFunction = null; let elseFunction = null; @@ -124,9 +127,12 @@ function _with(...args) { for (let i = 0; i < args.length; i++) { const [pattern, func] = args[i]; - const result = func(...argsToPass); + const result = await func(...argsToPass); - const patternResult = Core.Patterns.match_or_default(pattern, result); + const patternResult = await Core.Patterns.match_or_default_async( + pattern, + result + ); if (patternResult == null) { if (elseFunction) { diff --git a/test/support/main.ex b/test/support/main.ex index b8159547..a18d3d90 100644 --- a/test/support/main.ex +++ b/test/support/main.ex @@ -1,13 +1,5 @@ -defmodule User do - defstruct name: "John", age: 27 -end - defmodule Main do def start(:normal, [callback]) do callback.("started") - - a = %User{} - #:console.log(a.name) - #:console.log(a.age) end end diff --git a/yarn.lock b/yarn.lock index 88f8de3b..99135ecc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3712,8 +3712,9 @@ table@^4.0.1: slice-ansi "0.0.4" string-width "^2.0.0" -"tailored@file:/Users/bryanjos/projects/basstype/tailored": - version "2.7.0" +tailored@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/tailored/-/tailored-2.7.1.tgz#87858d309e7c17b22706207cd300c51d1c7cff80" dependencies: erlang-types "^1.0.1" From b570742a3220c369afb3f7caf50edd05754e6180 Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Sat, 26 Aug 2017 19:30:09 -0500 Subject: [PATCH 3/6] Save merge changes --- lib/elixir_script/passes/translate/forms/for.ex | 4 ---- package.json | 4 ---- yarn.lock | 6 ------ 3 files changed, 14 deletions(-) diff --git a/lib/elixir_script/passes/translate/forms/for.ex b/lib/elixir_script/passes/translate/forms/for.ex index 9bcbf10f..bde93d0a 100644 --- a/lib/elixir_script/passes/translate/forms/for.ex +++ b/lib/elixir_script/passes/translate/forms/for.ex @@ -27,12 +27,8 @@ defmodule ElixirScript.Translate.Forms.For do [JS.array_expression(args.patterns), fun, filter] ) -<<<<<<< HEAD - members = ["Elixir", "Collectable", "__load"] -======= members = ["Elixir", "Collectable" , "__load"] ->>>>>>> master collectable = Helpers.call( Identifier.make_namespace_members(members), [JS.identifier("Elixir")] diff --git a/package.json b/package.json index 2a71221f..f3f4ee39 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,7 @@ "license": "MIT", "dependencies": { "erlang-types": "^1.0.1", -<<<<<<< HEAD - "tailored": "^2.7.1" -======= "tailored": "^2.7.2" ->>>>>>> master }, "devDependencies": { "ava": "^0.21.0", diff --git a/yarn.lock b/yarn.lock index aa4bd121..90e2ea26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3712,15 +3712,9 @@ table@^4.0.1: slice-ansi "0.0.4" string-width "^2.0.0" -<<<<<<< HEAD -tailored@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/tailored/-/tailored-2.7.1.tgz#87858d309e7c17b22706207cd300c51d1c7cff80" -======= tailored@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/tailored/-/tailored-2.7.2.tgz#01ab31b9bcacdb33f44da7aaa54fd7beffa1bd0e" ->>>>>>> master dependencies: erlang-types "^1.0.1" From 0815fe2f8186c30f73eb354e9402261cf84da915 Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Sat, 26 Aug 2017 19:30:53 -0500 Subject: [PATCH 4/6] Fix one more merge conflict --- lib/elixir_script/passes/translate/forms/for.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/elixir_script/passes/translate/forms/for.ex b/lib/elixir_script/passes/translate/forms/for.ex index bde93d0a..ad3e9c0f 100644 --- a/lib/elixir_script/passes/translate/forms/for.ex +++ b/lib/elixir_script/passes/translate/forms/for.ex @@ -2,11 +2,7 @@ defmodule ElixirScript.Translate.Forms.For do @moduledoc false alias ESTree.Tools.Builder, as: JS -<<<<<<< HEAD - alias ElixirScript.Translate.{Form, Clause, Identifier, Helpers} -======= alias ElixirScript.Translate.{Form, Clause, Helpers, Identifier} ->>>>>>> master alias ElixirScript.Translate.Forms.Pattern def compile({:for, _, generators}, state) do From 72767c076c99a25bd299cd43d429c2c6d7556cd1 Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Wed, 30 Aug 2017 20:51:05 -0500 Subject: [PATCH 5/6] Update tests for functions turned to async functions --- src/javascript/tests/case.spec.js | 8 ++--- src/javascript/tests/cond.spec.js | 6 ++-- .../tests/core/erlang_compat/lists_spec.js | 8 ++--- .../tests/core/erlang_compat/maps_spec.js | 4 +-- src/javascript/tests/core/functions.spec.js | 21 ++++++------ src/javascript/tests/for.spec.js | 32 +++++++++---------- src/javascript/tests/try.spec.js | 4 +-- src/javascript/tests/with.spec.js | 23 +++++++------ 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/javascript/tests/case.spec.js b/src/javascript/tests/case.spec.js index 4b143edc..4de8a4da 100644 --- a/src/javascript/tests/case.spec.js +++ b/src/javascript/tests/case.spec.js @@ -5,7 +5,7 @@ const Patterns = Core.Patterns; const SpecialForms = Core.SpecialForms; const Tuple = Core.Tuple; -test('case', t => { +test('case', async t => { const clauses = [ Patterns.clause( [ @@ -13,7 +13,7 @@ test('case', t => { Symbol.for('selector'), Patterns.variable(), Patterns.variable() - ), + ) ], (i, value) => { return value; @@ -24,10 +24,10 @@ test('case', t => { ), Patterns.clause([Patterns.variable()], value => { return value; - }), + }) ]; - const result = SpecialForms._case('thing', clauses); + const result = await SpecialForms._case('thing', clauses); t.is(result, 'thing'); }); diff --git a/src/javascript/tests/cond.spec.js b/src/javascript/tests/cond.spec.js index 6d1d87e8..1ffcbfac 100644 --- a/src/javascript/tests/cond.spec.js +++ b/src/javascript/tests/cond.spec.js @@ -3,14 +3,14 @@ import Core from '../lib/core'; const SpecialForms = Core.SpecialForms; -test('cond', t => { +test('cond', async t => { const clauses = [ [1 + 1 === 1, () => 'This will never match'], [2 * 2 !== 4, () => 'Nor this'], - [true, () => 'This will'], + [true, () => 'This will'] ]; - const result = SpecialForms.cond(...clauses); + const result = await SpecialForms.cond(...clauses); t.is(result, 'This will'); }); diff --git a/src/javascript/tests/core/erlang_compat/lists_spec.js b/src/javascript/tests/core/erlang_compat/lists_spec.js index 491abd15..d39a40d5 100644 --- a/src/javascript/tests/core/erlang_compat/lists_spec.js +++ b/src/javascript/tests/core/erlang_compat/lists_spec.js @@ -16,13 +16,13 @@ test('flatten', t => { t.deepEqual(Core.lists.flatten([1, [[2], 3]]), [1, 2, 3]); }); -test('foldl', t => { - t.deepEqual(Core.lists.foldl((v, acc) => acc + v, 0, [1, 2, 3]), 6); +test('foldl', async t => { + t.deepEqual(await Core.lists.foldl((v, acc) => acc + v, 0, [1, 2, 3]), 6); }); -test('foldr', t => { +test('foldr', async t => { t.deepEqual( - Core.lists.foldr((v, acc) => acc + v.toString(), '', [1, 2, 3]), + await Core.lists.foldr((v, acc) => acc + v.toString(), '', [1, 2, 3]), '321' ); }); diff --git a/src/javascript/tests/core/erlang_compat/maps_spec.js b/src/javascript/tests/core/erlang_compat/maps_spec.js index ddb69aa9..cfb8fc5e 100644 --- a/src/javascript/tests/core/erlang_compat/maps_spec.js +++ b/src/javascript/tests/core/erlang_compat/maps_spec.js @@ -15,8 +15,8 @@ test('find', t => { t.deepEqual(result.values, [Symbol.for('ok'), 'b']); }); -test('fold', t => { +test('fold', async t => { const myMap = new Map([['a', 1], ['b', 2]]); - const result = Core.maps.fold((k, v, acc) => acc + v, 0, myMap); + const result = await Core.maps.fold((k, v, acc) => acc + v, 0, myMap); t.is(result, 3); }); diff --git a/src/javascript/tests/core/functions.spec.js b/src/javascript/tests/core/functions.spec.js index 005994ac..98692929 100644 --- a/src/javascript/tests/core/functions.spec.js +++ b/src/javascript/tests/core/functions.spec.js @@ -2,15 +2,18 @@ import test from 'ava'; import Core from '../../lib/core'; const Functions = Core.Functions; -test('call_property', t => { - t.is(Functions.call_property(1, 'toString'), '1'); - t.is(Functions.call_property([], 'toString'), ''); - t.is(Functions.call_property([], 'length'), 0); - t.is(Functions.call_property('', 'toString'), ''); - t.is(Functions.call_property('', 'length'), 0); - t.is(Functions.call_property(Symbol('test'), 'toString'), 'Symbol(test)'); - t.is(Functions.call_property({ completed: false }, 'completed'), false); - t.is(Functions.call_property({ id: 0 }, 'id'), 0); +test('call_property', async t => { + t.is(await Functions.call_property(1, 'toString'), '1'); + t.is(await Functions.call_property([], 'toString'), ''); + t.is(await Functions.call_property([], 'length'), 0); + t.is(await Functions.call_property('', 'toString'), ''); + t.is(await Functions.call_property('', 'length'), 0); + t.is( + await Functions.call_property(Symbol('test'), 'toString'), + 'Symbol(test)' + ); + t.is(await Functions.call_property({ completed: false }, 'completed'), false); + t.is(await Functions.call_property({ id: 0 }, 'id'), 0); }); test('split_at', t => { diff --git a/src/javascript/tests/for.spec.js b/src/javascript/tests/for.spec.js index 52e29d48..3846ad7f 100644 --- a/src/javascript/tests/for.spec.js +++ b/src/javascript/tests/for.spec.js @@ -14,8 +14,8 @@ const collectable = { [ $, Patterns.type(Tuple, { - values: [Symbol.for('cont'), Patterns.variable()], - }), + values: [Symbol.for('cont'), Patterns.variable()] + }) ], (list, x) => list.concat([x]) ), @@ -23,12 +23,12 @@ const collectable = { ); return new Tuple([], fun); - }, + } }; -test('simple for', t => { +test('simple for', async t => { const gen = Patterns.list_generator($, [1, 2, 3, 4]); - const result = SpecialForms._for( + const result = await SpecialForms._for( Patterns.clause([$], x => x * 2), [gen], collectable @@ -37,12 +37,12 @@ test('simple for', t => { t.deepEqual(result, [2, 4, 6, 8]); }); -test('for with multiple generators', t => { +test('for with multiple generators', async t => { //for x <- [1, 2], y <- [2, 3], do: x*y const gen = Patterns.list_generator($, [1, 2]); const gen2 = Patterns.list_generator($, [2, 3]); - const result = SpecialForms._for( + const result = await SpecialForms._for( Patterns.clause([$, $], (x, y) => x * y), [gen, gen2], collectable @@ -51,10 +51,10 @@ test('for with multiple generators', t => { t.deepEqual(result, [2, 3, 4, 6]); }); -test('for with filter', t => { +test('for with filter', async t => { //for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n const gen = Patterns.list_generator($, [1, 2, 3, 4, 5, 6]); - const result = SpecialForms._for( + const result = await SpecialForms._for( Patterns.clause([$], x => x, x => x % 2 === 0), [gen], collectable @@ -63,7 +63,7 @@ test('for with filter', t => { t.deepEqual(result, [2, 4, 6]); }); -test('for with pattern matching', t => { +test('for with pattern matching', async t => { //for {:user, name} <- [user: "john", admin: "john", user: "meg"], do // String.upcase(name) //end @@ -73,11 +73,11 @@ test('for with pattern matching', t => { [ [Symbol.for('user'), 'john'], [Symbol.for('admin'), 'john'], - [Symbol.for('user'), 'meg'], + [Symbol.for('user'), 'meg'] ] ); - const result = SpecialForms._for( + const result = await SpecialForms._for( Patterns.clause([[Symbol.for('user'), $]], name => name.toUpperCase()), [gen], collectable @@ -86,7 +86,7 @@ test('for with pattern matching', t => { t.deepEqual(result, ['JOHN', 'MEG']); }); -test('for with bitstring', t => { +test('for with bitstring', async t => { //for <> >>, do: {r, g, b} const gen = Patterns.bitstring_generator( @@ -117,17 +117,17 @@ test('for with bitstring', t => { BitString.integer({ value: $ }), BitString.integer({ value: $ }), BitString.integer({ value: $ }) - ), + ) ], (r, g, b) => new Tuple(r, g, b) ); - const result = SpecialForms._for(expression, [gen], collectable); + const result = await SpecialForms._for(expression, [gen], collectable); t.deepEqual(result, [ new Tuple(213, 45, 132), new Tuple(64, 76, 32), new Tuple(76, 0, 0), - new Tuple(234, 32, 15), + new Tuple(234, 32, 15) ]); }); diff --git a/src/javascript/tests/try.spec.js b/src/javascript/tests/try.spec.js index 440c7df9..cfaba3c0 100644 --- a/src/javascript/tests/try.spec.js +++ b/src/javascript/tests/try.spec.js @@ -3,7 +3,7 @@ import Core from '../lib/core'; const Patterns = Core.Patterns; const SpecialForms = Core.SpecialForms; -test('try', t => { +test('try', async t => { /* try do 1 / x @@ -18,7 +18,7 @@ test('try', t => { const x = 1; - const value = SpecialForms._try( + const value = await SpecialForms._try( () => { return 1 / x; }, diff --git a/src/javascript/tests/with.spec.js b/src/javascript/tests/with.spec.js index 924c844b..3db9588c 100644 --- a/src/javascript/tests/with.spec.js +++ b/src/javascript/tests/with.spec.js @@ -16,7 +16,7 @@ function map_fetch(map, key) { return Symbol.for('error'); } -test('with', t => { +test('with', async t => { /* opts = %{width: 10, height: 15} @@ -29,7 +29,7 @@ test('with', t => { const opts = { width: 10, height: 15 }; - const value = SpecialForms._with( + const value = await SpecialForms._with( [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], [new Tuple(Symbol.for('ok'), $), width => map_fetch(opts, 'height')], (width, height) => new Tuple(Symbol.for('ok'), width * height) @@ -38,7 +38,7 @@ test('with', t => { t.deepEqual(value, new Tuple(Symbol.for('ok'), 150)); }); -test('with without match', t => { +test('with without match', async t => { /* opts = %{width: 10} @@ -51,7 +51,7 @@ test('with without match', t => { const opts = { width: 10 }; - const value = SpecialForms._with( + const value = await SpecialForms._with( [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], [new Tuple(Symbol.for('ok'), $), width => map_fetch(opts, 'height')], (width, height) => new Tuple(Symbol.for('ok'), width * height) @@ -60,7 +60,7 @@ test('with without match', t => { t.deepEqual(value, Symbol.for('error')); }); -test('with bare expression', t => { +test('with bare expression', async t => { /* opts = %{width: 10} @@ -74,7 +74,7 @@ test('with bare expression', t => { const opts = { width: 10, height: 15 }; - const value = SpecialForms._with( + const value = await SpecialForms._with( [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], [$, width => width * 2], [ @@ -88,7 +88,7 @@ test('with bare expression', t => { t.deepEqual(value, new Tuple(Symbol.for('ok'), 300)); }); -test('with else', t => { +test('with else', async t => { /* opts = %{width: 10} @@ -104,7 +104,7 @@ test('with else', t => { const opts = { width: 10 }; - const value = SpecialForms._with( + const value = await SpecialForms._with( [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], [new Tuple(Symbol.for('ok'), $), width => map_fetch(opts, 'height')], (width, height) => new Tuple(Symbol.for('ok'), width * height), @@ -119,7 +119,7 @@ test('with else', t => { t.deepEqual(value, new Tuple(Symbol.for('error'), Symbol.for('wrong_data'))); }); -test('with else that don`t match', t => { +test('with else that don`t match', async t => { /* opts = %{width: 10} @@ -135,8 +135,7 @@ test('with else that don`t match', t => { const opts = { width: 10 }; - const withFunction = SpecialForms._with.bind( - null, + const withFunctionPromise = SpecialForms._with( [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], [new Tuple(Symbol.for('ok'), $), width => map_fetch(opts, 'height')], (width, height) => new Tuple(Symbol.for('ok'), width * height), @@ -148,5 +147,5 @@ test('with else that don`t match', t => { ) ); - t.throws(withFunction, MatchError); + await t.throws(withFunctionPromise, MatchError); }); From f0a3f6ce1d2c73a4e57f31ad0383b198cebb5ae4 Mon Sep 17 00:00:00 2001 From: Bryan Joseph Date: Sun, 3 Sep 2017 09:14:53 -0500 Subject: [PATCH 6/6] Fix leftover merge conflicts --- rollup.config.js | 17 ++------- src/javascript/lib/core/special_forms.js | 48 +++++------------------- 2 files changed, 13 insertions(+), 52 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 2df7d8ee..06b16f13 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -8,21 +8,12 @@ export default { plugins: [ nodeResolve({ jsnext: true }), babel({ -<<<<<<< HEAD - babelrc: false - }) - //minify({ - // keepFnName: true, - // keepClassName: true - //}) -======= babelrc: false, }), - minify({ - keepFnName: true, - keepClassName: true, - }), ->>>>>>> master + // minify({ + // keepFnName: true, + // keepClassName: true + // }) ], targets: [{ dest: 'priv/build/iife/ElixirScript.Core.js', format: 'iife' }], }; diff --git a/src/javascript/lib/core/special_forms.js b/src/javascript/lib/core/special_forms.js index f2a0f80e..c3f0c090 100644 --- a/src/javascript/lib/core/special_forms.js +++ b/src/javascript/lib/core/special_forms.js @@ -14,29 +14,9 @@ async function cond(...clauses) { throw new Error(); } -async function _for(expression, generators, collectable_protocol, into = []) { - let [result, fun] = collectable_protocol.into(into); - - const generatedValues = run_list_generators(generators.pop()(), generators); - - for (const value of generatedValues) { - if (await expression.guard.apply(this, value)) { - result = await fun( - result, - new Core.Tuple( - Symbol.for('cont'), - await expression.fn.apply(this, value) - ) - ); - } - } - - return fun(result, Symbol.for('done')); -} - function run_list_generators(generator, generators) { if (generators.length === 0) { - return generator.map(x => { + return generator.map((x) => { if (Array.isArray(x)) { return x; } @@ -55,31 +35,24 @@ function run_list_generators(generator, generators) { return run_list_generators(next_gen, generators); } -<<<<<<< HEAD -async function _try( - do_fun, - rescue_function, - catch_fun, - else_function, - after_function -) { -======= -function _for(expression, generators, collectable_protocol, into = []) { +async function _for(expression, generators, collectable_protocol, into = []) { let [result, fun] = collectable_protocol.into(into); const generatedValues = run_list_generators(generators.pop()(), generators); for (const value of generatedValues) { - if (expression.guard.apply(this, value)) { - result = fun(result, new Core.Tuple(Symbol.for('cont'), expression.fn.apply(this, value))); + if (await expression.guard.apply(this, value)) { + result = await fun( + result, + new Core.Tuple(Symbol.for('cont'), await expression.fn.apply(this, value)), + ); } } return fun(result, Symbol.for('done')); } -function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { ->>>>>>> master +async function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { let result = null; try { @@ -147,10 +120,7 @@ async function _with(...args) { const result = await func(...argsToPass); - const patternResult = await Core.Patterns.match_or_default_async( - pattern, - result - ); + const patternResult = await Core.Patterns.match_or_default_async(pattern, result); if (patternResult == null) { if (elseFunction) {