From 22cf9ced1189638d3705dea1cf5995ed0000cdf2 Mon Sep 17 00:00:00 2001 From: osolodo Date: Thu, 29 Mar 2018 15:06:07 +0100 Subject: [PATCH] Re-arranged corpus/src --- doc/corpus/src/TargetTestErlang.erl | 104 -- doc/corpus/src/asttrans.erl | 1066 ---------------- doc/corpus/src/core_AST_revEng.erl | 57 - doc/corpus/src/coregen.erl | 84 -- doc/corpus/src/datatype_atom.js | 76 -- doc/corpus/src/datatype_bitstring.js | 125 -- doc/corpus/src/datatype_erlangDatatype.js | 42 - doc/corpus/src/datatype_float.js | 70 -- doc/corpus/src/datatype_fun.js | 28 - doc/corpus/src/datatype_int.js | 90 -- doc/corpus/src/datatype_list.js | 200 --- doc/corpus/src/datatype_map.js | 106 -- doc/corpus/src/datatype_pid.js | 103 -- doc/corpus/src/datatype_port.js | 28 - doc/corpus/src/datatype_process.js | 79 -- doc/corpus/src/datatype_reference.js | 33 - doc/corpus/src/datatype_tuple.js | 115 -- doc/corpus/src/datatype_unbound.js | 24 - doc/corpus/src/demo.erl | 2 +- doc/corpus/src/esast.erl | 149 --- doc/corpus/src/estree.erl | 971 --------------- doc/corpus/src/jarlang.erl | 385 ------ doc/corpus/src/module_erlang.js | 1337 --------------------- doc/corpus/src/module_io.js | 327 ----- doc/corpus/src/tokdata.erl | 124 -- 25 files changed, 1 insertion(+), 5724 deletions(-) delete mode 100644 doc/corpus/src/TargetTestErlang.erl delete mode 100644 doc/corpus/src/asttrans.erl delete mode 100644 doc/corpus/src/core_AST_revEng.erl delete mode 100644 doc/corpus/src/coregen.erl delete mode 100644 doc/corpus/src/datatype_atom.js delete mode 100644 doc/corpus/src/datatype_bitstring.js delete mode 100644 doc/corpus/src/datatype_erlangDatatype.js delete mode 100644 doc/corpus/src/datatype_float.js delete mode 100644 doc/corpus/src/datatype_fun.js delete mode 100644 doc/corpus/src/datatype_int.js delete mode 100644 doc/corpus/src/datatype_list.js delete mode 100644 doc/corpus/src/datatype_map.js delete mode 100644 doc/corpus/src/datatype_pid.js delete mode 100644 doc/corpus/src/datatype_port.js delete mode 100644 doc/corpus/src/datatype_process.js delete mode 100644 doc/corpus/src/datatype_reference.js delete mode 100644 doc/corpus/src/datatype_tuple.js delete mode 100644 doc/corpus/src/datatype_unbound.js delete mode 100644 doc/corpus/src/esast.erl delete mode 100644 doc/corpus/src/estree.erl delete mode 100644 doc/corpus/src/jarlang.erl delete mode 100644 doc/corpus/src/module_erlang.js delete mode 100644 doc/corpus/src/module_io.js delete mode 100644 doc/corpus/src/tokdata.erl diff --git a/doc/corpus/src/TargetTestErlang.erl b/doc/corpus/src/TargetTestErlang.erl deleted file mode 100644 index 57e4d49..0000000 --- a/doc/corpus/src/TargetTestErlang.erl +++ /dev/null @@ -1,104 +0,0 @@ --module('TargetTestErlang'). --export([boolean/0, - integer/0, - string/0, - addition/1, - subtraction/1, - multiplication/1, - division/1, - remainder/1, - intDivision/1, - equality/2, - notEquality/2, - lessThan/2, - lessThanOrEq/2, - moreThan/2, - moreThanOrEq/2, - orTest/2, - andTest/2, - notTest/1, - xorTest/2, - borTest/2, - bandTest/2, - bnotTest/1, - bxorTest/2, - ifTest/1, - echo/1, - sequence/0, - errIfNot3/1, - errIfNot3Tuple/1, - errIfNot3and3/2, - caseExample/1, - caseWithCall/1]). - -boolean() -> true. -integer() -> 3. -string() ->"Hello, world!". - -addition(Var) -> Var + 3. -subtraction(Var) -> Var - 3. - -multiplication(Var) -> Var * 3. -division(Var) -> Var / 3. - -remainder(Var) -> Var rem 3. -intDivision(Var) -> Var div 3. - -equality(Var1,Var2)->Var1==Var2. -notEquality(Var1,Var2)->Var1/=Var2. -lessThan(Var1,Var2)->Var1Var1=Var1>Var2. -moreThanOrEq(Var1,Var2)->Var1>=Var2. - -orTest(Var1,Var2)->Var1 or Var2. -andTest(Var1,Var2)->Var1 and Var2. -notTest(Var)->not Var. -xorTest(Var1,Var2)->Var1 xor Var2. - -borTest(Var1,Var2)->Var1 bor Var2. -bandTest(Var1,Var2)->Var1 band Var2. -bnotTest(Var)->bnot Var. -bxorTest(Var1,Var2)->Var1 bxor Var2. - -ifTest(Var)-> - if - Var == 42 -> - "The meaning of life, the universe & everything"; - true -> - "= 6 x 9" - end. - -echo(Var)->Var. - -sequence() -> - io:format("A"), - io:format("B"), - io:format("C"). - -errIfNot3(Var) -> - 3 = Var. - -errIfNot3Tuple(Var) -> - {3,atom} = {Var,atom}. - -errIfNot3and3(Var,Var2) -> - {3,3} = {Var,Var2}. - -caseExample(Var)-> - case Var of - match -> - 42; - othermatch -> - not42; - _ -> nomatch - end. - -caseWithCall(Var)-> - Res = io:format(Var), - case Res of - nope -> - "Didn't work"; - ok -> - "ok" - end. diff --git a/doc/corpus/src/asttrans.erl b/doc/corpus/src/asttrans.erl deleted file mode 100644 index e4f4b42..0000000 --- a/doc/corpus/src/asttrans.erl +++ /dev/null @@ -1,1066 +0,0 @@ -%%% Module Description: -%%% Recursively descends into a core erlang AST and generates an ESTREE equivalent --module(asttrans). --author(["Andrew Johnson", "Chris Bailey", "Nick Laine"]). - --define(VERSION, "2.1.0"). - --vsn(?VERSION). - -%%% Export all functions if we compiled with erlc -dTEST or c(?MODULE, {d, 'TEST'}). -%%% This is so that we can run external eunit tests --ifdef(TEST). - -compile(export_all). --else. - -export([erast_to_esast/2]). --endif. - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - MODULE ENTRYPOINTS ------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Alternative entrypoint to parse_module/1 -erast_to_esast(AST, ConcMode) -> - parse_module(AST, ConcMode). - -%% Begins parses ast expecting a c_module atom to indicate that the ast we're parsing -%% is indeed a core_erlang ast. -%% Processes information we need such as ModuleName and continues to parse functions and -%% module export information. -parse_module({c_module, _A, {_, _, ModuleName}, Exports, _Attributes, Functions}, ConcMode) -> - FormattedFunctions = parse_functions(Functions, ConcMode), - FormattedExports = lists:map( - fun({N, A}) ->{atom_to_list(N), A} end, - tuple_list_get_vars_3(Exports) - ), - esast:c_module(atom_to_list(ModuleName), FormattedExports, FormattedFunctions); -parse_module(T, _ConcMode) -> - io:format("Unrecognised Token in module section: ~p", [T]). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Concurrently parse all functions in the module --------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_functions(Functions, multi_threaded) -> - Self = self(), - Pids = lists:map( - fun(X) -> - spawn_link(fun() -> Self ! {self(), parse_function(X)} end) - end, Functions - ), - [ - receive - {Pid, TranspiledFunction} -> - TranspiledFunction - end - || - Pid <- Pids - ]; -parse_functions(Functions, single_threaded) -> - [parse_function(Function) || Function <- Functions]. - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a funcion node ----------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% Compiler generated functions are currently generated as an empty function. -parse_function({{_, _, {FunctionName, Arity}}, {_c_fun, [compiler_generated], _, _}}) -> - {atom_to_list(FunctionName) ++ "/" ++ integer_to_list(Arity), function_wrap([], [])}; -parse_function({{_, _, {FunctionName, Arity}}, {_c_fun, _, ParamNames, Body}}) -> - { - atom_to_list(FunctionName) ++ "/" ++ integer_to_list(Arity), - function_wrap( - lists:map(fun(N) -> parse_var(noreturn, [], N) end, ParamNames), - parse_node(return, tuple_list_get_vars_3(ParamNames), Body) - ) - }. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Select the appropriate node parsing funciton ----------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% Dividing the pattern matching in this way makes the stack traces easier to read -parse_node(ReturnAtom, Params, N) -> - case tuple_getVar_1(N) of - c_call -> parse_call(ReturnAtom, Params, N); - c_var -> parse_var(ReturnAtom, Params, N); - c_seq -> parse_seq(ReturnAtom, Params, N); - c_let -> parse_let(ReturnAtom, Params, N); - c_apply -> parse_apply(ReturnAtom, Params, N); - c_literal -> parse_literal(ReturnAtom, Params, N); - c_tuple -> parse_tuple(ReturnAtom, Params, N); - c_cons -> parse_cons(ReturnAtom, Params, N); - c_try -> parse_try(ReturnAtom, Params, N); - c_primop -> parse_primop(ReturnAtom, Params, N); - c_letrec -> parse_letrec(ReturnAtom, Params, N); - c_receive -> parse_receive(ReturnAtom, Params, N); - c_case -> parse_case(ReturnAtom, Params, N) - end. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a function call node ----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_call(return, Params, {c_call, A, {B, C, Module}, {D, E, FunctionName}, Parameters}) -> - estree:return_statement( - parse_call(noreturn, Params, {c_call, A, {B, C, Module}, {D, E, FunctionName}, Parameters}) - ); -parse_call(noreturn, Params, {c_call, _, {_, _, Module}, {_, _, FunctionName}, Parameters}) -> - estree:call_expression( - estree:call_expression( - estree:member_expression( - estree:member_expression( - estree:identifier(atom_to_binary(Module, utf8)), - estree:literal(atom_to_binary(FunctionName, utf8)), - true), - estree:identifier(<<"bind">>), - false - ), - [estree:this_expression()] - ), - lists:map(fun(T) -> parse_node(noreturn, Parameters, T) end, Parameters) - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the use of a variable ---------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_var(return, Params, {c_var, A, Var}) -> - estree:return_statement(parse_var(noreturn, Params, {c_var, A, Var})); -%added for support of functions by name -parse_var(noreturn, Params, {c_var, _, {Name, Arity}}) -> - estree:identifier(atom_to_list(Name) ++ "/" ++ integer_to_list(Arity)); -parse_var(noreturn, Params, {c_var, _, Var}) -> - estree:identifier(atom_to_binary(Var, utf8)). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a sequence of nodes -----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% If the first node is a receive node the second node must be passed as a parameter to be called -%% inside the receive wrapping. -parse_seq(ReturnAtom, Params, {c_seq, _, A={c_receive,_,_,_,_}, B}) -> - parse_node(noreturn, - {next,{ReturnAtom, Params, B}}, A); -parse_seq(ReturnAtom, Params, {c_seq, _, A, B}) -> - assemble_sequence( - parse_node(noreturn, Params, A), - parse_node(ReturnAtom, Params, B)). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the assinment of a variable for immediate use ---------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% A let statement is the core erlang representation of implicit variable declaration -%% Often the result of some function as an argument of another function. -parse_let(ReturnAtom, Params, {c_let, _, [{_, _, Variable}], Value, UsedBy}) -> - assemble_sequence( - estree:variable_declaration( - [estree:variable_declarator( - estree:identifier(atom_to_binary(Variable, utf8)), - parse_node(noreturn, Params, Value)) - ], - <<"let">> - ), - parse_node(ReturnAtom, Params, UsedBy)). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the call of a local function --------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_apply(ReturnAtom, Params, {c_apply, _, {_, _, {FunctionName, Arity}}, Parameters}) -> - parse_call(ReturnAtom, Params, {c_call, [], {a, a, functions}, - {a, a, list_to_atom(atom_to_list(FunctionName) ++ "/" ++ integer_to_list(Arity))}, - Parameters} - ); -parse_apply(ReturnAtom, Params, {c_apply, _, {_, _, FunctionName}, Parameters}) -> - parse_call(ReturnAtom, Params, - {c_call, [], {a, a, functions}, {a, a, FunctionName}, Parameters} - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the use of a literal ----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% Note that a list of literals is also a literal, -%% but that the internal values are represented as actual literals, not literal nodes. -parse_literal(return, Params, {c_literal, _, Value}) -> - estree:return_statement(parse_literal(noreturn, Params, {c_literal, [], Value})); -parse_literal(noreturn, Params, {c_literal, _, Value}) when is_integer(Value) -> - estree:new_expression(estree:identifier(<<"Int">>), [estree:literal(Value)]); -parse_literal(noreturn, Params, {c_literal, _, Value}) when is_float(Value) -> - estree:new_expression(estree:identifier(<<"Float">>), [estree:literal(Value)]); -parse_literal(noreturn, Params, {c_literal, _, Value}) when is_atom(Value) -> - estree:new_expression( - estree:identifier(<<"Atom">>), [estree:literal(atom_to_binary(Value, utf8))] - ); - -parse_literal(noreturn, Params, {c_literal, _, Value}) when is_list(Value) -> - estree:new_expression(estree:identifier(<<"List">>), lists:map(fun(Elem) -> - parse_literal(noreturn, Params, {c_literal, [], Elem}) - end, Value)); -parse_literal(noreturn, Params, {c_literal, _, Value}) when is_tuple(Value) -> - estree:new_expression(estree:identifier(<<"Tuple">>), - case tup_to_list(Value) of - [] -> []; - Array -> [parse_literal(return, Params, {c_literal, [], A}) || A <- Array] - end - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the definition of a tuple that doesn't contain only literals ------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_tuple(return, Params, A={c_tuple, _, Values}) -> - estree:return_statement(parse_tuple(noreturn, Params, A)); -parse_tuple(noreturn, Params, {c_tuple, _, Values}) -> - estree:new_expression( - estree:identifier(<<"Tuple">>), [parse_node(noreturn, Params, Value) || Value <- Values] - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse the definition of a list that doesn't contain only literals -------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% This function parses the start of the list -parse_cons(return,Params,{c_cons,_,A,B})-> - estree:return_statement(parse_cons(noreturn,Params,{c_cons,[],A,B})); -parse_cons(noreturn,Params,{c_cons,_,A,B})-> - {Values,End} = parse_cons_chain(noreturn,Params,{c_cons,[],A,B}), - NewList = estree:new_expression(estree:identifier(<<"List">>),Values), - estree:call_expression( - estree:member_expression(NewList,estree:identifier(<<"cons">>),false), - [End] - ). - -%% This function parses the rest of the list -parse_cons_chain(noreturn,Params,{c_cons,[],A,B={c_cons,_,C,D}})-> - {Values,End} = parse_cons_chain(noreturn,[],B), - {[parse_node(noreturn,Params,A)|Values],End}; -parse_cons_chain(noreturn,Params,{c_cons,[],A,B})-> - {[parse_node(noreturn,Params,A)],parse_node(noreturn,Params,B)}. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Naively parse a try wrapper, assuming it has no actual purpose ----------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% c_try nodes are not associated with actual try blocks in erlang, but instead generated by the -%% compiler around some functions when used in a guard. -parse_try(return, Params, {c_try, _, Elem, _, _, _, _}) -> - estree:return_statement(parse_try(noreturn, Params, {c_try, [], Elem, a, a, a, a})); -parse_try(noreturn, Params, {c_try, _, Elem, _, _, _, _}) -> - estree:call_expression( - function_wrap( - [], - parse_node(return, Params, Elem) - ), - []). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Naively parse the creation of an error message --------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% c_primop has so far only been observed as an error message -parse_primop(return, Params, {c_primop, _, {_, _, Type}, _Details}) -> - estree:error( - atom_to_list(Type), - "TODO Errors dont parse nicely\\n", estree:literal(<<"Message">>) - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a list comprehension ----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% TODO: List comprehensions are always created with the same ID, multiple concurrent list -%% comprehensions will behave incorrectly until they are defined in an appropriate scope -parse_letrec(ReturnAtom, Params, {c_letrec, _, [Func], Apply}) -> - {Id, F} = parse_function(Func), - assemble_sequence( - estree:assignment_expression( - <<"=">>, - estree:member_expression( - estree:identifier(<<"functions">>), - estree:literal(list_to_binary(Id)), - true - ), - F - ), - parse_node(ReturnAtom, Params, Apply) - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a message receive block -------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% TODO: This is still a work in progress, it will not produce viable JS. -%% Code to be executed after the receive is passed in the parameters var. -parse_receive(ReturnAtom, Params, {c_receive,_,Clauses,Timeout,TimeoutConsequent})-> - case Params of - {next,{A,B,C}} -> Next = - [estree:if_statement( - estree:identifier(<<"__doNext">>), - estree:call_expression( - estree:member_expression( - estree:identifier(<<"this">>), - estree:identifier(<<"setBehaviour">>), - false - ), - [function_wrap([],parse_node(A,B,C))] - ),null - )], - RealParams = B; - _ -> Next = [], - RealParams = Params - end, - [ - estree:variable_declaration([estree:variable_declarator( - estree:identifier(<<"__mIndex">>),estree:literal(0))], - <<"let">> - ), - estree:call_expression( - estree:member_expression( - estree:identifier(<<"this">>), - estree:identifier(<<"setBehaviour">>), - false - ), - [ - function_wrap([], - [ - estree:variable_declaration([ - estree:variable_declarator( - estree:identifier(<<"__doNext">>),estree:literal(true)), - estree:variable_declarator( - estree:identifier(<<"__doLoop">>),estree:literal(false))], - <<"let">> - ), - - estree:do_while_statement( - estree:identifier(<<"__doLoop">>), - estree:block_statement([ - estree:expression_statement( - estree:assignment_expression( - <<"=">>, - estree:identifier(<<"__doLoop">>), - estree:literal(false) - ) - ), - estree:if_statement( - estree:binary_expression(<<">=">>, - estree:identifier(<<"__mIndex">>), - estree:member_expression( - estree:member_expression( - estree:this_expression(), - estree:identifier(<<"messages">>), - false - ), - estree:identifier(<<"length">>), - false - ) - ), - estree:block_statement([ - estree:expression_statement( - estree:call_expression( - estree:member_expression( - estree:this_expression(), - estree:identifier(<<"restartBehaviour">>), - false - ),[] - ) - ), - estree:expression_statement( - estree:assignment_expression( - <<"=">>, - estree:identifier(<<"__doNext">>), - estree:literal(false) - ) - ) - ]), - estree:block_statement([ - estree:variable_declaration([ - estree:variable_declarator( - estree:identifier(<<"__message">>), - estree:member_expression( - estree:member_expression( - estree:this_expression(), - estree:identifier(<<"messages">>), - false - ), - estree:identifier(<<"__mIndex">>), - true - ) - )], - <<"let">> - ), - parse_receive_clauses( - ReturnAtom, - RealParams, - [{c_var, a, '__message'}], - Clauses) - ]) - ) - - ]) - ) - |Next] - ) - ] - ) - ]. - -% estree:call_expression( -% estree:member_expression( -% estree:identifier(<<"TODO">>), -% estree:identifier(<<"receive_placeholder">>), -% false -% ),[] -% ) - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse receive clauses ---------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_receive_clauses(ReturnAtom, Params, Vars, []) -> - []; -parse_receive_clauses(ReturnAtom, Params, Vars, - [{c_clause, _, Match, Evaluate, Consequent}|Clauses]) -> - % Parse the remaining clauses first. - ElseClauses = parse_receive_clauses(ReturnAtom, Params, Vars, Clauses), - % If there are no remaining clauses then use null - case ElseClauses of - [] -> ElseClausesActual = estree:block_statement([ - estree:expression_statement( - estree:update_expression( - <<"++">>, - estree:identifier(<<"__mIndex">>), - false - ) - ), - estree:expression_statement( - estree:assignment_expression( - <<"=">>, - estree:identifier(<<"__doLoop">>), - estree:literal(true) - ) - ) - ]); - _ -> ElseClausesActual = ElseClauses - end, - {DefineL, MatchL, AssignL} = extract_clause_snippets(Params,Vars,Match), - % Assemble the if statement - estree:if_statement( - % The function that serves as pattern patching and guards - assemble_case_condition(Params, {DefineL, MatchL, AssignL}, Evaluate), - estree:block_statement( - assemble_sequence( - estree:expression_statement( - estree:call_expression( - estree:member_expression( - estree:member_expression( - estree:this_expression(), - estree:identifier(<<"messages">>), - false - ), - estree:identifier(<<"splice">>), - false - ), - [estree:identifier(<<"__mIndex">>), - estree:literal(1)] - ) - ), - assemble_sequence( - % Assign the variables that are used in the match - assign_matched_vars(Params, DefineL, AssignL), - encapsulate_expressions( - list_check( - parse_node(ReturnAtom, Params, Consequent) - ) - ) - ) - ) - ), - ElseClausesActual %alternate - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a case block's opening nodes --------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% For simplicity cases of a single var are converted to multi-var case format -parse_case(ReturnAtom, Params, {c_case, _, {c_var, _, Var}, Clauses}) -> - parse_case(ReturnAtom, Params, {c_case, a, {c_values, a, [{c_var, a, Var}]}, Clauses}); -parse_case(ReturnAtom, Params, {c_case, _, {c_values, _, Vars}, Clauses}) -> - parse_case_clauses(ReturnAtom, Params, Vars, Clauses); - -%% Cases that take a function call as an input are parsed here. -%% This one parses local functions. -parse_case(ReturnAtom, Params, {c_case, _, A={c_apply, _, {c_var, _, Fun}, Args}, Clauses}) -> - parse_function_case(ReturnAtom, Params,parse_node(noreturn, Params, A),Clauses); -%% And this one parses external functions. -parse_case(ReturnAtom, Params, - {c_case, _, C={c_call, _, {c_literal, _, Module}, {c_literal, _, FunctionName}, Args}, Clauses} - ) -> - parse_function_case(ReturnAtom, Params,parse_node(noreturn, Params, C),Clauses). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse a case block that takes a function --------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% In a break from the standard through the rest of the parsing functions, this function takes a -%% pre-parsed function call. -%% The result of the function is assigned to a temp variable ant that is used in a regular case -%% block. -parse_function_case(ReturnAtom, Params, FuncCall, Clauses) -> - TempVar = lists:append(atom_to_list('_tempVar_'),get_random_string(6)), - assemble_sequence( - %Define temp variable & call function - estree:variable_declaration([estree:variable_declarator( - estree:identifier(list_to_binary(TempVar)), - estree:call_expression(estree:member_expression( - estree:identifier(<<"jrts">>),estree:identifier(<<"jsToErlang">>),false), - [FuncCall] - ) - )], <<"let">>), - %Continue as normal, passing the temp variable - parse_case(ReturnAtom, Params, {c_case, [], {c_var, [], list_to_atom(TempVar)}, Clauses}) - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Parse case clauses ------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -parse_case_clauses(ReturnAtom, Params, Vars, []) -> - []; -parse_case_clauses(ReturnAtom, Params, Vars, - [{c_clause, _, Match, Evaluate, Consequent}|Clauses]) -> - % Parse the remaining clauses first. - ElseClauses = parse_case_clauses(ReturnAtom, Params, Vars, Clauses), - % If there are no remaining clauses then use null - case ElseClauses of - [] -> ElseClausesActual = null; - _ -> ElseClausesActual = ElseClauses - end, - {DefineL, MatchL, AssignL} = extract_clause_snippets(Params,Vars,Match), - % Assemble the if statement - estree:if_statement( - % The function that serves as pattern patching and guards - assemble_case_condition(Params, {DefineL, MatchL, AssignL}, Evaluate), - estree:block_statement( - assemble_sequence( - % Assign the variables that are used in the match - % At this point in development it should be un-nessisary to filter for un-parsed - % variables, but I'll leave it here until I next review the case clauses. - assign_matched_vars(Params, DefineL, AssignL), - encapsulate_expressions( - list_check( - parse_node(ReturnAtom, Params, Consequent) - ) - ) - ) - ), - ElseClausesActual %alternate - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Create code snippets for matching ---------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -% This extracts the relevant variables for declaration, matching and assignment -extract_clause_snippets(Params,Vars,Match)-> - lists:foldl( - fun(Elem, {DefineL, MatchL, AssignL}) -> - case Elem of - {{c_var, _, ParamName}, {c_var, A, NewName}}-> - {lists:append(DefineL, [ - estree:variable_declarator( - estree:identifier(atom_to_binary(NewName, utf8)), - estree:identifier(atom_to_binary(ParamName, utf8)) - ) - ]), MatchL, AssignL}; - - {V={c_var, _, ParamName}, M={c_literal, _, Literal}}-> - {DefineL, - lists:append(MatchL,[ - estree:call_expression( - estree:member_expression( - parse_node(noreturn,Params,V), - estree:identifier(<<"match">>), - false - ), - [parse_node(noreturn,Params,M)] - ) - ]),AssignL}; - - {V={c_var, _, ParamName}, M={c_cons, _, H, T}}-> - {lists:append(DefineL, - recurse_var_declaration(M) - ), - lists:append(MatchL,[ - estree:call_expression( - estree:member_expression( - parse_node(noreturn,Params,V), - estree:identifier(<<"match">>), - false - ), - [parse_node(noreturn,Params,M)] - ) - ]), - lists:append(AssignL,recurse_var_assignments( - M, - estree:identifier(atom_to_binary(ParamName, utf8)) - ))}; - - {V={c_var, _, ParamName}, M={c_tuple, _, Content}}-> - {lists:append(DefineL, - recurse_var_declaration(M) - ), - lists:append(MatchL,[ - estree:call_expression( - estree:member_expression( - parse_node(noreturn,Params,V), - estree:identifier(<<"match">>), - false - ), - [parse_node(noreturn,Params,M)] - ) - ]), - lists:append(AssignL, recurse_var_assignments( - M, - estree:identifier(atom_to_binary(ParamName, utf8)) - ))}; - - {V={c_var, _, ParamName}, {c_alias, _, {c_var, _, NewName}, M}}-> - {lists:append(DefineL, - recurse_var_declaration(M) - ), - lists:append(MatchL,[ - estree:call_expression( - estree:member_expression( - parse_node(noreturn,Params,V), - estree:identifier(<<"match">>), - false - ), - [parse_node(noreturn,Params,M)] - ) - ]), - lists:append(AssignL, lists:append( - recurse_var_assignments( - M, - estree:identifier(atom_to_binary(ParamName, utf8)) - ), - [ - estree:assignment_expression( - <<"=">>, - estree:identifier(atom_to_binary(NewName, utf8)), - estree:identifier(atom_to_binary(ParamName, utf8)) - ) - ] - ))} - end - end, - {[], [], []}, - lists:zip(Vars, Match)). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Make the clause condition self contained --------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% This allows the involved variables to be correctly scoped, and later defined. -%% This one shortcuts guard only matching -assemble_case_condition(Params, {_, [], _}, Evaluate) -> - estree:call_expression( - function_wrap( - [], - parse_node(return, Params, Evaluate) - ), - []); -assemble_case_condition(Params, {DefineL, MatchL, AssignL}, Evaluate) -> - - % Check if any declarations are actually needed after matching - case AssignL of - [] -> Declaration2Actual = []; - _ -> Declaration2Actual = estree:variable_declaration(list_check(AssignL), <<"let">>) - end, - % Create the internal logic of the clause condition function. Including actual match calls and - % the evaluation of the guard. - Internal = estree:if_statement( - assemble_match_calls(MatchL), - estree:block_statement(%consequent - encapsulate_expressions( - list_check( - assemble_sequence( - Declaration2Actual, - parse_node(return, Params, Evaluate) - ) - ) - ) - ), - null - ), - % Check that variables actually need to be defined before matching is done - case DefineL of - [] -> InternalActual = Internal; - _ -> InternalActual = assemble_sequence( - estree:variable_declaration(list_check(DefineL), <<"let">>), - Internal - ) - end, - % Finally return the call of the clause condition - estree:call_expression( - estree:call_expression( - estree:member_expression( - function_wrap( - [], - InternalActual - ), - estree:identifier(<<"bind">>), - false), - [estree:this_expression()]), - []). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Recursively generate a list of variable declarations --------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -recurse_var_declaration({c_var, _, Name}) -> - [estree:variable_declarator( - estree:identifier(atom_to_binary(Name, utf8)), - estree:identifier(<<"null">>) - )]; -recurse_var_declaration({c_literal, _, Name}) -> - []; -recurse_var_declaration({c_tuple, _, Elements}) -> - lists:foldl(fun(Elem, L) -> - lists:append(L, recurse_var_declaration(Elem)) - end, [], Elements); -recurse_var_declaration({c_cons, _, A, B}) -> - lists:append(recurse_var_declaration(A), - recurse_var_declaration(B)). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Recursively generate a list of variable assignments ---------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -recurse_var_assignments(M, V) -> - recurse_var_assignments(0, M, V, false). -recurse_var_assignments(_, {c_var, _, Name}, V, false) -> - [ - estree:assignment_expression( - <<"=">>, - estree:identifier(atom_to_binary(Name, utf8)), - V - ) - ]; -% Assign the remainder of a list -recurse_var_assignments(ConsCount, {c_var, _, Name}, V, isTail) -> - [ - estree:assignment_expression( - <<"=">>, - estree:identifier(atom_to_binary(Name, utf8)), - estree:call_expression( - estree:member_expression(V, estree:identifier(<<"nthSeg">>), false), - [estree:literal(ConsCount)] - ) - ) - ]; -recurse_var_assignments(_, {c_tuple, _, Elements}, V, _) -> - {_,L} = lists:foldl( - fun(Elem, {I,L}) -> - {I+1, - lists:append( - L, - recurse_var_assignments(0, Elem, - %estree:expression_statement( - estree:call_expression( - estree:member_expression(V, - estree:identifier(<<"nth">>), false), - [estree:literal(I)] - ) - ,%), - false - ) - )} - end, - {0,[]}, Elements), - L;%Return just the list - -% These two detect a list and begin counting the position in the list -% This one detects that a list constructor ends with a tail binding -recurse_var_assignments(ConsCount, {c_cons, _, A, B={c_var, _, Name}}, V, _) -> - lists:append( - recurse_var_assignments(0, A, - estree:call_expression( - estree:member_expression(V, - estree:identifier(<<"nth">>), false), - [estree:literal(ConsCount)] - ), - false), - recurse_var_assignments(ConsCount+1, B, V, isTail) - ); -recurse_var_assignments(ConsCount, {c_cons, _, A, B}, V, _) -> - lists:append( - recurse_var_assignments(0, A, - estree:call_expression( - estree:member_expression(V, - estree:identifier(<<"nth">>), false), - [estree:literal(ConsCount)] - ), - false), - recurse_var_assignments(ConsCount+1, B, V, false) - ); -recurse_var_assignments(_ConsCount, _, _V, _) -> - []. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Chain together all calls to match patterns ------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -assemble_match_calls(MatchL) -> - case MatchL of - [] -> estree:literal(true); - [M] -> M; - [M|T] -> estree:logical_expression(<<"&&">>, M, assemble_match_calls(T)) - end. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Assign variables after matching -----------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -% TODO: Review this when cases are next reviewed. -assign_matched_vars(Params, DefineL, AssignL) -> - % Check that variables actually need to be defined before matching is done - case DefineL of - [] -> DefActual = []; - _ -> DefActual = estree:variable_declaration(list_check(DefineL), <<"let">>) - end, - % Check if any assignments are needed after matching - case AssignL of - [] -> AssignActual = []; - _ -> AssignActual = list_check(AssignL) - end, - %Output as a list - assemble_sequence(DefActual,AssignActual). - - - - - - - - - - - -% assign_matched_vars(Params, [V], [M]) -> -% assign_matched_vars(Params, V, M); -% assign_matched_vars(Params, [V|Vars], [M|Match]) -> -% assemble_sequence( -% assign_matched_vars(Params, [V], [M]), -% assign_matched_vars(Params, Vars, Match) -% ); -% assign_matched_vars(Params, {c_var, _, Variable}, {c_var, _, Match}) -> -% [estree:expression_statement( -% estree:assignment_expression( -% <<"=">>, -% estree:identifier(atom_to_binary(Match, utf8)), -% estree:identifier(atom_to_binary(Variable, utf8)) -% ) -% )]; -% assign_matched_vars(Params, {c_var, _, Variable}, {c_alias, _, {c_var, [], Name}, _Value}) -> -% [estree:expression_statement( -% estree:assignment_expression( -% <<"=">>, -% estree:identifier(atom_to_binary(Name, utf8)), -% estree:identifier(atom_to_binary(Variable, utf8)) -% ) -% )]; -% %assign_matched_vars(Params, A, B) -> -% assign_matched_vars(Params, _, _) -> -% [ok]. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Append two lists, even if they weren't lists to start with --------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -assemble_sequence(L, R) when is_list(L) and is_list(R) -> - lists:append(L, R); -assemble_sequence(L, R) when is_list(R) -> - [L|R]; -assemble_sequence(L, R) when is_list(L) -> - lists:append(L, [R]); -assemble_sequence(L, R) -> - [L, R]. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Get the third value from each tuple for a list of tuples ----------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -tuple_list_get_vars_3([]) -> - []; -tuple_list_get_vars_3([{_, _, Val} | Body]) -> - [Val | tuple_list_get_vars_3(Body)]; -tuple_list_get_vars_3([{_, _, Val, _} | Body]) -> - [Val | tuple_list_get_vars_3(Body)]. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Get the second value from each tuple for a list of tuples ---------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -tuple_list_get_vars_2([]) -> - []; -tuple_list_get_vars_2([{_, Val} | Body]) -> - [Val | tuple_list_get_vars_2(Body)]; -tuple_list_get_vars_2([{_, Val, _} | Body]) -> - [Val | tuple_list_get_vars_2(Body)]. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Get the first value from each tuple for a list of tuples ----------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -tuple_getVar_1({V}) -> V; -tuple_getVar_1({V, _}) -> V; -tuple_getVar_1({V, _, _}) -> V; -tuple_getVar_1({V, _, _, _}) -> V; -tuple_getVar_1({V, _, _, _, _}) -> V; -tuple_getVar_1({V, _, _, _, _, _}) -> V; -tuple_getVar_1({V, _, _, _, _, _, _}) -> V. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Create a list of variable declarators from a variable list --------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -declarators_from_list(List) -> - lists:filtermap(fun(Elem) -> - case Elem of - {c_var, _, Name} -> { true, {Name, - estree:variable_declarator( - estree:identifier(atom_to_binary(Name, utf8)), - estree:identifier(<<"null">>))}}; - {c_alias, _, {c_var, _, Name}, Value} -> {true, {Name, - estree:variable_declarator( - estree:identifier(atom_to_binary(Name, utf8)), - parse_node(noreturn, [], Value))}}; - _ -> false - end - end, List). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Convert a tuple to a list -----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -tup_to_list(Tuple) -> tup_to_list(Tuple, 1, tuple_size(Tuple)). - -tup_to_list(Tuple, Pos, Size) when Pos =< Size -> - [element(Pos, Tuple) | tup_to_list(Tuple, Pos+1, Size)]; -tup_to_list(_Tuple, _Pos, _Size) -> []. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Wrap one or more nodes in a function, with an optional list of parameters -----------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -function_wrap(Identifier_list,Body_nodes) -> -estree:function_expression( - null, - Identifier_list, - estree:block_statement( - encapsulate_expressions( - list_check( - Body_nodes - ) - ) - ), - false - ). - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Check the parsed input is a Statement or Declaration --------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -%% Helper function to determine whether a given ESTree node is a statement -is_statement({_, Type, _}) -> - case re:run(atom_to_list(Type), "Statement|Declaration") of - {match, _} -> - true; - _ -> - false - end; -is_statement(_) -> - false. - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Encapsulate any non-Expression in a list --------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -encapsulate_expressions(L) -> - lists:map( - fun(X) -> - IsStmt = is_statement(X), - if - IsStmt->X; - true->estree:expression_statement(X) - end - end, - L - ). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - Check that the input is a list, but also not a list within a list -------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% -list_check([L]) when is_list(L) ->%un-nest lists - list_check(L); -list_check(L) -> - IsList = is_list(L), - if - IsList->L; - true->[L] - end. - - - -get_random_string(Length)-> - get_random_string(Length, [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]). -get_random_string(Length, AllowedChars) -> - lists:foldl(fun(_, Acc) -> - atom_to_list(lists:nth(random:uniform(length(AllowedChars)), - AllowedChars)) - ++ Acc - end, [], lists:seq(1, Length)). \ No newline at end of file diff --git a/doc/corpus/src/core_AST_revEng.erl b/doc/corpus/src/core_AST_revEng.erl deleted file mode 100644 index b61f5f9..0000000 --- a/doc/corpus/src/core_AST_revEng.erl +++ /dev/null @@ -1,57 +0,0 @@ --module(core_AST_revEng). --export([boolean/0, - integer/0, - string/0, - addition/1, - subtraction/1, - multiplication/1, - division/1, - remainder/1, - intDivision/1, - equality/2, - notEquality/2, - lessThan/2, - lessThanOrEq/2, - moreThan/2, - moreThanOrEq/2, - orTest/2, - andTest/2, - notTest/1, - xorTest/2, - borTest/2, - bandTest/2, - bnotTest/1, - bxorTest/2, - echo/1]). - -boolean() -> true. -integer() -> 3. -string() ->"Hello, world!". - -addition(Var) -> Var + 3. -subtraction(Var) -> Var - 3. - -multiplication(Var) -> Var * 3. -division(Var) -> Var / 3. - -remainder(Var) -> Var rem 3. -intDivision(Var) -> Var div 3. - -equality(Var1,Var2)->Var1==Var2. -notEquality(Var1,Var2)->Var1/=Var2. -lessThan(Var1,Var2)->Var1Var1=Var1>Var2. -moreThanOrEq(Var1,Var2)->Var1>=Var2. - -orTest(Var1,Var2)->Var1 or Var2. -andTest(Var1,Var2)->Var1 and Var2. -notTest(Var)->not Var. -xorTest(Var1,Var2)->Var1 xor Var2. - -borTest(Var1,Var2)->Var1 bor Var2. -bandTest(Var1,Var2)->Var1 band Var2. -bnotTest(Var)->bnot Var. -bxorTest(Var1,Var2)->Var1 bxor Var2. - -echo(Var)->Var. diff --git a/doc/corpus/src/coregen.erl b/doc/corpus/src/coregen.erl deleted file mode 100644 index 9073ad6..0000000 --- a/doc/corpus/src/coregen.erl +++ /dev/null @@ -1,84 +0,0 @@ -%%% Module Description: -%%% Compiles Erlang Source code to Core Erlang --module(coregen). --author(["Chris Bailey", "Andrew Johnson"]). --vsn(1.0). - --export([to_core_erlang/1, - to_core_erlang/2, - to_core_erlang_ast/1, - to_core_erlang_ast/2]). - -%% Compiles a given Erlang source file to a CoreErlang file, and writes the resultant -%% CoreErlang output to a file in the same directory as the given module -to_core_erlang(Module) -> - to_core_erlang(Module, filepath:path(Module)). - -%% Compiles a given Erlang source file to a CoreErlang file, and returns the raw result -%% to the caller of this function. -to_core_erlang(Module, return) -> - compile:file(Module, [to_core, binary]); - -%% Compiles a given Erlang source file to a CoreErlang file, and writes the resultant -%% CoreErlang output to the given OutputDirectory -to_core_erlang(Module, OutputDirectory) -> - case re:run(OutputDirectory, ".*/$") of - nomatch -> - {error, output_directory_not_valid}; - _ -> - compile:file(Module, to_core), - - % Compiling always generates output in working directory so lets - % move it into the directory where source code exists - FileName = filepath:name(Module), - OldLocation = FileName ++ ".core", - NewLocation = OutputDirectory ++ OldLocation, - - filepath:move(OldLocation, NewLocation), - {ok, core_compiled} - end. - -%% Compiles a given Erlang source file to a CoreErlang AST file, and writes the resultant -%% CoreErlang AST output to a file in the same directory as the given module -to_core_erlang_ast(Module) -> - to_core_erlang_ast(Module, filepath:path(Module)). - -%% Compiles a given Erlang source file to a CoreErlang AST file, and returns the raw result -%% to the caller of this function. -to_core_erlang_ast(Module, return) -> - ModuleName = filepath:name(Module), - to_core_erlang(Module, "./"), % Write Core Erlang source for given module so we can - % read it to scan and parse - - case file:read_file(ModuleName ++ ".core") of - {ok, Bin} -> - case core_scan:string(binary_to_list(Bin)) of - {ok, Toks, _} -> - Result = core_parse:parse(Toks); - {error, E, _} -> - Result = {error, {scan, E}} - end; - {error, E} -> - Result = {error, {read, E}} - end, - - file:delete(ModuleName ++ ".core"), - Result; - -%% Compiles a given Erlang source file to a CoreErlang AST file, and writes the resultant -%% CoreErlang AST output to a file in the given output directory -to_core_erlang_ast(Module, OutputDirectory) -> - ModuleName = filepath:name(Module), - case to_core_erlang_ast(Module, return) of - {ok, AST} -> - % Write the .core file - to_core_erlang(Module, OutputDirectory), - - % Write AST - file:write_file(OutputDirectory ++ ModuleName ++ ".ast", - lists:flatten(io_lib:format("~p", [AST]))), - - {ok, ast_compiled}; - {error, E} -> - {error, E} - end. \ No newline at end of file diff --git a/doc/corpus/src/datatype_atom.js b/doc/corpus/src/datatype_atom.js deleted file mode 100644 index b21aec8..0000000 --- a/doc/corpus/src/datatype_atom.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Class constructor for representing atoms - * Defining atoms also adds the atom to a global atoms table in JRTS - */ - -const Atom = (() => { - // Private registerAtom token - const registerAtom = Symbol("registerAtom"); - const registered = Symbol("registered"); - - return class Atom extends ErlangDatatype { - constructor(name) { - super(); - this.value = name; - this.precedence = 1; - - this[registerAtom](); - } - - match(other) { - if (other===null||(Atom.isAtom(other) ? this.getValue() === other.getValue() : this.getValue() === other)) { - return other; - } - else { - return undefined; - } - } - - toString() { - return `${this.getValue()}`; - } - - registerPid(p) { - if (Pid.isPid(p)) { - if (jrts.atoms[this.value] === registered) { - jrts.atoms[this.value] = p; - } - else { - throw "** exception error: this atom has already been registered to a different Pid"; - } - } - else { - throw "** exception error: you can only register a Pid to an Atom with a Pid"; - } - } - - [registerAtom]() { - try { - if (!jrts.atoms[this.value]) { - jrts.atoms[this.value] = registered; - } - } - catch (e) { - console.warn(`Atom '${this.getValue()}' could not be registered to runtime atom table as it doesn't seem to exist`); - } - } - - static isAtom(a) { - return a instanceof Atom; - } - - static cloneAtom(a) { - return a; - } - - static exists(name) { - try { - return !!jrts.atoms[a]; - } - catch (e) { - console.warn(`Could not check if Atom '${name}' exists in atom table as atom table doesn't seem to exist`); - return false; - } - } - }; -})(); diff --git a/doc/corpus/src/datatype_bitstring.js b/doc/corpus/src/datatype_bitstring.js deleted file mode 100644 index 2f3dc20..0000000 --- a/doc/corpus/src/datatype_bitstring.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Class constructor for representing BitStrings in Jarlang's runtime - */ - -const defaultSize = 8; - -const BitString = (() => { - return class BitString extends ErlangDatatype { - constructor() { - super(); - - this.precedence = 10; - this.value = { - values: [], - sizes: [] - }; - - // Process arguments - const args = [...arguments]; - var arg; - - while ((arg = args.shift()) !== undefined) { - if (typeof arg == "string" || List.isString(arg)) { - arg.toString().split("").forEach((c) => { - this.value.values.push(c.charCodeAt(0)); - this.value.sizes.push(defaultSize); - }); - } - else if (arg[1] !== 0) { - if (!Array.isArray(arg)) { - arg = [arg]; - } - - if (!Number.isInteger(arg[0])) { - throw `BitString: Bad argument ${arg[0]}`; - } - - if (1 in arg && arg[1] !== defaultSize) { - if (!Number.isInteger(arg[1]) || arg[1] < 0) { - throw `BitString: Bad argument ${arg[1]}`; - } - - if (arg[1] > defaultSize) { - this.value.values.push(arg[1] > defaultSize * 2 ? 0 : - arg[0] >> (arg[1] - defaultSize)); - this.value.sizes.push(defaultSize); - args.unshift([arg[0], arg[1] - defaultSize]); - } - else { - this.value.values.push(arg[0] % (1 << arg[1])); - this.value.sizes.push(arg[1]); - } - } - else { - this.value.values.push(arg[0] % (1 << defaultSize)); - this.value.sizes.push(defaultSize); - } - } - } - } - - [Symbol.iterator]() { - var tmp = [...this.getValue().values], v; - - return { - next: () => { - if ((v = tmp.shift()) !== undefined) { - return { - value: v, - done: false - }; - } - return { - done: true - }; - } - } - } - - toString() { - if (!this.getValue().values.length) { - return "<<>>"; - } - - var vals = new List(...this.getValue().values); - - if (BitString.isBinary(this)) { - if (List.isString(vals)) { - return `<<"${vals}">>`; - } - return `<<${this.getValue().values.join(",")}>>`; - } - - vals = [...vals]; - var sizes = [...this.getValue().sizes], tmp = [], i; - - while (i = sizes.shift()) { - if (i !== defaultSize) { - tmp.push(`${vals.shift()}:${i}`); - } - else { - tmp.push(vals.shift()); - } - } - return `<<${tmp.join(",")}>>`; - } - - match(other) { - if (other === null || (BitString.isBitString(other) && this.value === other.value)) { - return other; - } - else { - return undefined; - } - } - - static isBitString(a) { - return a instanceof BitString; - } - - static isBinary(a) { - return a instanceof BitString && a.getValue().sizes.every((s) => s === defaultSize); - } - }; -})(); diff --git a/doc/corpus/src/datatype_erlangDatatype.js b/doc/corpus/src/datatype_erlangDatatype.js deleted file mode 100644 index bb1a8ec..0000000 --- a/doc/corpus/src/datatype_erlangDatatype.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Class constructor for representing generic erlang datatypes - * This is intended to be inherited by other erlang datatype classes - */ - -const ErlangDatatype = (() => { - return class ErlangDatatype { - constructor() { - this.value = 0; - this.precedence = 0; - } - - getValue() { - return this.value; - } - - toString() { - return this.value.toString(); - } - - match(other) { - if (other===null || (ErlangDatatype.isErlangDatatype(other) ? this.getValue() === other.getValue() : this.getValue() === other)) { - return other; - } - else { - return undefined; - } - } - - isUnbound() { - return false; - } - - getComparator() { - return this.precedence; - } - - static isErlangDatatype(a) { - return a instanceof ErlangDatatype; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_float.js b/doc/corpus/src/datatype_float.js deleted file mode 100644 index 1f2418f..0000000 --- a/doc/corpus/src/datatype_float.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Class constructor for representing Erlang floats in Jarlang's runtime - */ - -const Float = (() => { - return class Float extends ErlangDatatype { - constructor(val) { - super(); - this.value = val instanceof BigNumber ? val : new BigNumber(val); - this.precedence = 0; - } - - toString() { - return this.getValue().toString(); - } - - match(other) { - if (other===null||(!isNaN(other) && this.equals(other))) { - return other; - } - else { - return undefined; - } - } - - add(val) { - return new Float(this.value.plus((val instanceof Int || val instanceof Float) ? val.getValue() : val)); - } - - subtract(val) { - return new Float(this.value.minus((val instanceof Int || val instanceof Float) ? val.getValue() : val)); - } - - multiply(val) { - return new Float(this.value.times((val instanceof Int || val instanceof Float) ? val.getValue() : val)); - } - - divide(val) { - return new Float(this.value.div((val instanceof Int || val instanceof Float) ? val.getValue() : val)); - } - - equals(val) { - return this.value.equals((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - lessThan(val) { - return this.value.lessThan((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - lessThanOrEq(val) { - return this.value.lessThanOrEqualTo((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - greaterThan(val) { - return this.value.greaterThan((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - greaterThanOrEq(val) { - return this.value.greaterThanOrEqualTo((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - static isFloat(a) { - return a instanceof Float; - } - - static cloneFloat(n) { - return new Float(this.getValue()); - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_fun.js b/doc/corpus/src/datatype_fun.js deleted file mode 100644 index 8c86ae9..0000000 --- a/doc/corpus/src/datatype_fun.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Class constructor for representing Erlang funs in Jarlang's runtime - */ - -const Fun = (() => { - return class Fun extends ErlangDatatype { - constructor() { - super(); - this.precedence = 3; - } - - getValue() { - throw "Fun is not implemented yet"; - } - - toString() { - throw "Fun is not implemented yet"; - } - - match(other) { - throw "Fun is not implemented yet"; - } - - static isFun(a) { - return a instanceof Fun; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_int.js b/doc/corpus/src/datatype_int.js deleted file mode 100644 index 6b04faf..0000000 --- a/doc/corpus/src/datatype_int.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Class constructor for representing Erlang ints in Jarlang's runtime - */ - -const Int = (() => { - return class Int extends ErlangDatatype { - constructor(val) { - super(); - this.value = val instanceof BigNumber ? val : new BigNumber(val); - this.precedence = 0; - } - - toString() { - return this.getValue().toString(); - } - - match(other) { - if (other==null||(!isNaN(other) && this.equals(other))) { - return this; - } - else { - return undefined; - } - } - - add(val) { - if (val instanceof Float) { - return new Float(this.value.plus(val.getValue())); - } - return new Int(this.value.plus(val instanceof Int ? val.getValue() : val)); - } - - subtract(val) { - if (val instanceof Float) { - return new Float(this.value.minus(val.getValue())); - } - return new Int(this.value.minus(val instanceof Int ? val.getValue() : val)); - } - - multiply(val) { - if (val instanceof Float) { - return new Float(this.value.times(val.getValue())); - } - return new Int(this.value.times(val instanceof Int ? val.getValue() : val)); - } - - divide(val) { - if (val instanceof Float || !this.remainder(val).equals(0)) { - return new Float(this.value.div((val instanceof Int || val instanceof Float) ? val.getValue() : val)); - } - return new Int(this.value.div(val instanceof Int ? val.getValue() : val)); - } - - intDivide(val) { - return new Int(this.value.divToInt(val instanceof Int ? val.getValue() : val)); - } - - remainder(val) { - return new Int(this.value.mod(val instanceof Int ? val.getValue() : val)); - } - - equals(val) { - return this.value.equals((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - lessThan(val) { - return this.value.lessThan((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - lessThanOrEq(val) { - return this.value.lessThanOrEqualTo((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - greaterThan(val) { - return this.value.greaterThan((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - greaterThanOrEq(val) { - return this.value.greaterThanOrEqualTo((val instanceof Int || val instanceof Float) ? val.getValue() : val); - } - - static isInt(a) { - return a instanceof Int; - } - - static cloneInt(n) { - return new Int(this.getValue()); - } - }; -})(); diff --git a/doc/corpus/src/datatype_list.js b/doc/corpus/src/datatype_list.js deleted file mode 100644 index 7c8c424..0000000 --- a/doc/corpus/src/datatype_list.js +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Class constructor for representing Erlang lists in Jarlang's runtime - */ - -const List = (() => { - // Private nthNode token - const nthNode = Symbol("nthNode"); - - // Private last token - const last = Symbol("last"); - - // Private isLatin1Char token - const isLatin1Char = Symbol("isLatin1Char"); - - return class List extends ErlangDatatype { - constructor(car, ...cdr) { - super(); - if (typeof car === "string") { - var chars = car.split(""); - - for (var i = 0; i < chars.length; i++) { - chars[i] = chars[i].charCodeAt(0); - } - - this.value = new List(...chars); - } - else { - this.value = car; - } - - this.next = car !== undefined ? new List(...cdr) : undefined; - this.iterator = this; - this.precedence = 9; - } - - [nthNode](n) { - if (n < 0 || n >= this.size()) { - throw "index out of bounds error"; - } - - let i = 0; - let walker = this; - - while (i < n) { - walker = walker.next; - i++; - } - - return walker; - } - - [last]() { - return this.size() === 0 ? this : this[nthNode](this.size() - 1); - } - - [Symbol.iterator]() { - return { - next: () => { - // If the next node of the current iterator isn't another list OR is an empty list, then we know - // we have reached the end of the linked list - let isLastNode = !this.iterator || this.iterator.next === undefined || List.isEmptyList(this.iterator.next); - let v = List.isList(this.iterator) ? this.iterator.value : this.iterator; - - if (this.iterator === "done" || List.isEmptyList(this)) { - this.iterator = this; - return { - done: true - }; - } - else { - this.iterator = isLastNode ? "done" : this.iterator.next; - return { - value: v, - done: false - }; - } - } - }; - } - - nth(n) { - let nth = this[nthNode](n); - return List.isList(nth) ? nth.value : nth; - } - - nthSeg(n){ - return this[nthNode](n); - } - - size() { - return [...this].length; - } - - cons(appendage) { - let clone = List.cloneList(this); - clone[last]().next = appendage; - return clone; - } - - getValue() { - return [...this]; - } - - toString() { - let buffer = [...this]; - - if (buffer.length) { - let textBuffer = ""; - let isString = List.isString(this); - let isImproperList = !List.isList(this[nthNode](Math.max(0, buffer.length - 1))); - - for (let i = 0; i < buffer.length; i++) { - if (!isString) { - if (i > 0) { - if (i === buffer.length - 1 && isImproperList) { - textBuffer += "|"; - } - else { - textBuffer += ","; - } - } - textBuffer += buffer[i]; - } else { - textBuffer += String.fromCharCode(buffer[i]); - } - } - - return isString ? textBuffer : `[${textBuffer}]`; - } - - return '[]'; - } - - match(other) { - if(other===null)return this; - if (List.isList(other)) { - - if(this.nth(0).match(other.nth(0))){//If the first values match - if(other.next==null)return this;//Improper list (tail match) - let a= this.next().match(other.next()); - if(a!=undefined) return this; - } - return undefined; - // for (let i = 0; i < this.size(); i++) { - // if (ErlangDatatype.isErlangDatatype(this.nth(i))) { - // if(other===null)return this; - // if (this.nth(i).match(other.nth(i)) === undefined) { - // return undefined; - // } - // } - // else { - // if (this.nth(i) !== other.nth(i) && other.nth(i) !== null) { - // return undefined; - // } - // } - // } - // return other; - } - else { - return undefined; - } - } - - static isList(a) { - return a instanceof List; - } - - static isEmptyList(a) { - return List.isList(a) && a.value === undefined && a.next === undefined; - } - - static [isLatin1Char](c) { - if (Number.isInteger(c)) { - return (c >= 32 && c <= 126) || (c >= 160 && c <= 255) || (c === 10); - } - - if (Int.isInt(c)) { - return (c.greaterThanOrEq(32) && c.lessThanOrEq(126)) || (c.greaterThanOrEq(160) && c.lessThanOrEq(255)) || (c.equals(10)); - } - return false; - } - - static isString(a) { - if (!List.isList(a)) { - return false; - } - - for (var i = 0; i < a.size(); i++) { - if (!List[isLatin1Char](a.nth(i))) { - return false; - } - } - return true; - } - - static cloneList(a) { - return new List(...a); - } - }; -})(); diff --git a/doc/corpus/src/datatype_map.js b/doc/corpus/src/datatype_map.js deleted file mode 100644 index b53bc37..0000000 --- a/doc/corpus/src/datatype_map.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Class constructor for representing Erlang maps in Jarlang's runtime - */ - -const Map = (() => { - return class Map extends ErlangDatatype { - constructor(keys, values) { - super(); - - this.value = { - keys: keys, - values: values - }; - this.precedence = 7; - } - - [Symbol.iterator]() { - let k, - tmp1 = [...this.getValue().keys], - tmp2 = [...this.getValue().values]; - - return { - next: () => { - if (k = tmp1.shift()) { - return { - value: new Tuple(k, tmp2.shift()), - done: false - }; - } - return { - done: true - }; - } - }; - } - - get(key) { - if (key instanceof ErlangDatatype) { - for (let i = 0; i < this.getValue().keys.length; i++) { - if (key.match(this.getValue().keys[i])) { - return this.getValue().values[i]; - } - } - } - throw "bad key"; //todo - } - - put(key, value) { - this.value.keys.push(key); - this.value.values.push(value); - } - - update(key, value) { - if (key instanceof ErlangDatatype) { - for (let i = 0; i < this.getValue().keys.length; i++) { - if (key.match(this.getValue().keys[i])) { - this.value.values.splice(i, 1, value); - return; - } - } - } - throw "bad key"; //todo - } - - remove(key) { - if (key instanceof ErlangDatatype) { - for (let i = 0; i < this.getValue().keys.length; i++) { - if (key.match(this.getValue().keys[i])) { - this.value.keys.splice(i, 1); - this.value.values.splice(i, 1); - return; - } - } - } - } - - size() { - return this.getValue().keys.length; - } - - // todo: Ensure keys are ordered as they are in erlang - toString() { - let k, pairs = [], - tmp1 = [...this.getValue().keys], - tmp2 = [...this.getValue().values]; - - while ((k = tmp1.shift())) { - pairs.push(`${k}=>${tmp2.shift()}`); - } - return `#{${pairs.sort().join(", ")}}`; - } - - // TODO: actually implement mapping properly - match(map) { - if (map===null || (Map.isMap(map) && this.equals(map.getValue()))) { - return map; - } else { - return undefined; - } - } - - static isMap(m) { - return m instanceof Map; - } - }; -})(); diff --git a/doc/corpus/src/datatype_pid.js b/doc/corpus/src/datatype_pid.js deleted file mode 100644 index 898ea56..0000000 --- a/doc/corpus/src/datatype_pid.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Class constructor for representing Erlang PIDs in Jarlang's runtime - */ - -const Pid = (() => { - // Private rng token - const rng = Symbol("rng"); - - return class Pid extends ErlangDatatype { - constructor(arg) { - super(); - if (arguments.length === 3) { - this.node = arguments[0]; - this.id_a = arguments[1]; - this.id_b = arguments[2]; - } - else if (arg !== undefined && typeof (arg) === "function") { - let res = arg(); - if (Array.isArray(res) && res.length === 3) { - this.node = res[0]; - this.id_a = res[1]; - this.id_b = res[2]; - } - else if (res.node && res.id_a && res.id_b) { - this.node = res.node; - this.id_a = res.id_a; - this.id_b = res.id_b; - } - else { - this.node = res.toString(); - this.id_a = res.toString(); - this.id_b = res.toString(); - } - } - else if (arg !== undefined && arg.toString !== undefined) { - if (Array.isArray(arg) && arg.length === 3) { - this.node = arg[0]; - this.id_a = arg[1]; - this.id_b = arg[2]; - } - else if (arg.node && arg.id_a && arg.id_b) { - this.node = arg.node; - this.id_a = arg.id_a; - this.id_b = arg.id_b; - } - else { - this.node = arg.toString(); - this.id_a = arg.toString(); - this.id_b = arg.toString(); - } - } - else { - this.node = 0; - this.id_a = Pid[rng](0, 32767); // Max is 15 bits - this.id_b = Pid[rng](0, 7); // Max is 3 bits - } - - this.precedence = 5; - this.value = this; - } - - getValue() { - return [this.node, this.id_a, this.id_b]; - } - - getResult(noConvertToJs) { - const procValue = Process.getProcess(this).value; - if (noConvertToJs) { - return procValue; - } - else { - return jrts.erlangToJs(procValue); - } - } - - toString() { - return `<${this.node}.${this.id_a}.${this.id_b}>`; - } - - match(x) { - if (x===null || (Pid.isPid(x) && this.getValue().toString() === x.getValue().toString())) { - return x; - } - else { - return undefined; - } - } - - sendMessage(msg) { - return Process.getProcess(this).sendMessage(msg); - } - - static [rng](min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min)) + min; - } - - static isPid(m) { - return m instanceof Pid; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_port.js b/doc/corpus/src/datatype_port.js deleted file mode 100644 index beeb24b..0000000 --- a/doc/corpus/src/datatype_port.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Class constructor for representing Erlang ports in Jarlang's runtime - */ - -const Port = (() => { - return class Port extends ErlangDatatype { - constructor() { - super(); - this.precedence = 4; - } - - getValue() { - throw "Port is not implemented yet"; - } - - toString() { - throw "Port is not implemented yet"; - } - - match(other) { - throw "Port is not implemented yet"; - } - - static isPort(a) { - return a instanceof Port; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_process.js b/doc/corpus/src/datatype_process.js deleted file mode 100644 index f088e4c..0000000 --- a/doc/corpus/src/datatype_process.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Class constructor for representing Erlang Processes in Jarlang's runtime - */ - -const Process = (() => { - // Private registerProcess token - const registerProcess = Symbol("registerProcess"); - - return class Process extends ErlangDatatype { - constructor(lambda, pidGenerator) { - super(); - this.pid = pidGenerator !== undefined ? new Pid(pidGenerator) : new Pid(); - this.lambdas = [lambda]; - this.currentLambda = false; - this.messages = []; - this.stack = {}; - this.value = null; - this.lastRun = Date.now(); - - this[registerProcess](); - } - - toString() { - return this.pid.toString(); - } - - sendMessage(msg) { - return this.messages.push(msg); - } - - getValue() { - return this.pid; - } - - matchMessages(lambda) { - const unmatchedMessages = []; - const matchedMessages = this.messages.filter((message) => { - let predicatePasses = lambda(message); - if (predicatePasses) { - return true; - } - else { - unmatchedMessages.push(message); - } - }); - this.messages = unmatchedMessages; - return matchedMessages; - } - - setBehaviour(fn) { - this.lambdas.push(fn); - } - - restartBehaviour() { - this.lambdas.push(this.currentLambda); - } - - [registerProcess]() { - jrts.pids[this.pid.toString()] = jrts.processes.length; - jrts.processes.push(this); - } - - static isProcess(process) { - return process instanceof Process; - } - - static sendMessage(pid, msg) { - return Process.getProcess(pid).sendMessage(msg); - } - - static getProcess(v) { - return jrts.processes[(Atom.isAtom(v) ? jrts.pids[jrts.atoms[v.getValue()].toString()] : jrts.pids[v.toString()])]; - } - - static spawn(lambda, pidGenerator) { - return jrts.spawn(lambda, pidGenerator); - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_reference.js b/doc/corpus/src/datatype_reference.js deleted file mode 100644 index b2d5fa6..0000000 --- a/doc/corpus/src/datatype_reference.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Class constructor for representing Erlang References in Jarlang's runtime - */ - -const Reference = (() => { - // Private last token - let refCount = 0; - - return class Reference extends ErlangDatatype { - constructor() { - super(); - this.value = ++refCount; - this.precedence = 2; - } - - toString() { - return "#Ref<"+this.value.toString()+">"; - } - - match(x) { - if (x===null || (Reference.isReference(x) && this.value === x.value)) { - return x; - } - else { - return undefined; - } - } - - static isReference(r) { - return r instanceof Reference; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_tuple.js b/doc/corpus/src/datatype_tuple.js deleted file mode 100644 index 800426d..0000000 --- a/doc/corpus/src/datatype_tuple.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Class constructor for representing Erlang Tuples in Jarlang's runtime - */ - -const Tuple = (() => { - // Private nthNode token - const nthNode = Symbol("nthNode"); - - // Private last token - const last = Symbol("last"); - - return class Tuple extends ErlangDatatype { - constructor(car, ...cdr) { - super(); - this.val = car; - this.next = car !== undefined ? new Tuple(...cdr) : undefined; - - this.iterator = this; - this.precedence = 6; - } - - nth(n) { - let nth = this[nthNode](n); - return Tuple.isTuple(nth) ? nth.val : nth; - } - - size() { - return [...this].length; - } - - value() { - return [...this]; - } - - toString() { - return `{${[...this].join(",")}}`; - } - - [nthNode](n) { - if (n < 0 || n >= this.size()) { - throw "index out of bounds error"; - } - - let i = 0; - let walker = this; - - while (i < n) { - walker = walker.next; - i++; - } - - return walker; - } - - [Symbol.iterator]() { - return { - next: () => { - let v = this.iterator.val; - - if (this.iterator === undefined || Tuple.isEmptyTuple(this.iterator)) { - this.iterator = this; - return { - done: true - }; - } - else { - this.iterator = this.iterator.next; - return { - value: v, - done: false - }; - } - } - }; - } - - [last]() { - return this.size() === 0 ? this : this[nthNode](this.size() - 1); - } - - static isTuple(t) { - return t instanceof Tuple; - } - - static isEmptyTuple(tuple) { - return Tuple.isTuple(tuple) && tuple.val === undefined && tuple.next === undefined; - } - - static cloneTuple(tuple) { - return new Tuple(...tuple); - } - - match(other) { - if(other===null)return other; - if (Tuple.isTuple(other) && this.size() === other.size()) { - for (let i = 0; i < this.size(); i++) { - if (ErlangDatatype.isErlangDatatype(this.nth(i))) { - if (this.nth(i).match(other.nth(i)) === undefined) { - return undefined; - } - } - else { - if (this.nth(i) !== other.nth(i) && other.nth(i) !== null) { - return undefined; - } - } - } - return other; - } - else { - return undefined; - } - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/datatype_unbound.js b/doc/corpus/src/datatype_unbound.js deleted file mode 100644 index 8f880b2..0000000 --- a/doc/corpus/src/datatype_unbound.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Class constructor for representing Erlang Unbounds in Jarlang's runtime - */ - -const Unbound = (() => { - return class Unbound extends ErlangDatatype { - constructor() { - super(); - this.value = ++refCount; - } - - toString() { - return "unbound"; - } - - match(x) { - return x; - } - - static isUnbound(x) { - return x instanceof Unbound; - } - }; -})(); \ No newline at end of file diff --git a/doc/corpus/src/demo.erl b/doc/corpus/src/demo.erl index 8f6b268..0a0491b 100644 --- a/doc/corpus/src/demo.erl +++ b/doc/corpus/src/demo.erl @@ -6,7 +6,7 @@ stdout_example(String) -> arith_example() -> A = 13 * 5, - B = 120 / 12, + B = 99.5 / 12, C = 3 div 2, D = 12 rem 4, E = 15 rem 4, diff --git a/doc/corpus/src/esast.erl b/doc/corpus/src/esast.erl deleted file mode 100644 index 8f99dca..0000000 --- a/doc/corpus/src/esast.erl +++ /dev/null @@ -1,149 +0,0 @@ -%%% Module to help build valid JavaScript AST Nodes and trees --module(esast). --author(["Chris Bailey"]). --vsn(1.0). - --compile(export_all). - -%% Helper function to generate a equivalent c_module node in JS when given -%% the main attributes of a c_module node from a Core Erlang AST -c_module(ModuleName, ExportList, FunctionList) -> - % Export list looks like [{"Funcname", Arity}...] - % Function list looks like [{"Funcname/Arity", esast:functionDeclaration or esast:functionExpression}] - % ?spec([{ModuleName, list}, {ExportList, list_of_tuple}, {FunctionList, list_of_tuple}]), - estree:program([ - estree:const_declaration( - list_to_binary(ModuleName), - estree:call_expression( - estree:function_expression( - null, - [], - estree:block_statement([ - estree:use_strict(), - c_exports(ExportList), - c_functions(FunctionList), - estree:return_statement( - estree:identifier(<<"exports">>))]), - false), - []))]). - -%% Eventually creates an export list which is intended to be returned in a c_module call. -%% Function arity is handled with switch/case statements and as we don't know how many different -%% versions of a function there are, we store a map of lists of functions to call. We then turn -%% each entry in the map into a function containing a switch/case statement on arg length. -c_exports(ExportList) -> - MappedByFuncName = c_exports_mapfuncs(ExportList, #{}), - estree:const_declaration( - <<"exports">>, - estree:object_expression( - lists:map(fun({FuncName, Arities}) -> - estree:property( - estree:literal(list_to_binary(FuncName)), - estree:function_expression( - null, - [], - estree:block_statement( - c_exports_gencases({FuncName, Arities}) - ), - false)) - end, maps:to_list(MappedByFuncName)))). - -%% Function which takes a list of tuples in the form {Key, Value} and generates a map in the -%% form #{Key => ListOfAllValuesBelongingToKey} -c_exports_mapfuncs([], Map) -> - Map; -c_exports_mapfuncs([{FnName, FnArity} | Tails], Map) when is_list(FnName) , is_integer(FnArity) -> - case maps:find(FnName, Map) of - {ok, Val} -> - NewVal = Val ++ [FnArity]; - _ -> - NewVal = [FnArity] - end, - c_exports_mapfuncs(Tails, maps:put(FnName, NewVal, Map)). - -%% Generates a switch statement for use in c_exports node. Takes a tuple representing function -%% name and arities belonging to said function name. Cases will be generated for all such arities -c_exports_gencases({FuncName, Arities}) when is_list(FuncName) -> - [ - estree:const_declaration( - <<"args">>, - estree:call_expression( - estree:member_expression( - estree:array_expression([ - estree:spread_element( - estree:identifier(<<"arguments">>))]), - estree:identifier(<<"map">>), - false), - [estree:arrow_function_expression( - [estree:identifier(<<"arg">>)], - [], - null, - estree:call_expression( - estree:member_expression( - estree:identifier(<<"jrts">>), - estree:identifier(<<"jsToErlang">>), - false), - [estree:identifier(<<"arg">>)]), - false, - true)])), - estree:switch_statement( - estree:member_expression( - estree:identifier(<<"arguments">>), - estree:identifier(<<"length">>), - false), - lists:map(fun(Arity) -> - FunctionCall = estree:block_statement([estree:return_statement( - estree:call_expression( - estree:call_expression( - estree:member_expression( - estree:member_expression( - estree:identifier(<<"functions">>), - estree:literal(iolist_to_binary([ - FuncName, "/", integer_to_binary(Arity)])), - true), - estree:identifier(<<"bind">>), - false), - [estree:this_expression()]), - [estree:spread_element(estree:identifier(<<"args">>))]))]), - estree:switch_case( - estree:literal(Arity), - [estree:if_statement( - estree:call_expression( - estree:member_expression( - estree:identifier(<<"Process">>), - estree:identifier(<<"isProcess">>), - false), - [estree:this_expression()]), - FunctionCall, - estree:block_statement([estree:return_statement( - estree:call_expression( - estree:member_expression( - estree:identifier(<<"jrts">>), - estree:identifier(<<"spawn">>), - false), - [estree:function_expression(null, [], FunctionCall, false)]))]))]) - end, Arities), - false), - estree:error("exception error", "undefined function", - estree:binary_expression(<<"+">>, - estree:literal(list_to_binary(FuncName)), - estree:binary_expression(<<"+">>, - estree:literal(<<"/">>), - estree:member_expression( - estree:identifier(<<"arguments">>), - estree:identifier(<<"length">>), - false))))]. - -%% Generates function datastructure which takes a list in the form of [{"SomeFun/2", FUNCTION}] where function -%% is an ESTree functionExpression / functionDeclaration and produces the following: -%% const functions = {"somefun/2": function() { ... }} -c_functions([{FuncNameWithArity, Function} | Rest]) -> - FunctionList = [{FuncNameWithArity, Function} | Rest], - estree:const_declaration( - <<"functions">>, - estree:object_expression( - lists:map(fun({FuncName, FuncBody}) -> - estree:property( - estree:literal(list_to_binary(FuncName)), - FuncBody) - end , FunctionList))). \ No newline at end of file diff --git a/doc/corpus/src/estree.erl b/doc/corpus/src/estree.erl deleted file mode 100644 index c7ea39f..0000000 --- a/doc/corpus/src/estree.erl +++ /dev/null @@ -1,971 +0,0 @@ -%%% Erlang implementation of the MDN documentation for the JavaScript AST which you can find here: -%%% https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API - --module(estree). --author(["Chris Bailey"]). - --define(VERSION, "2.0.0"). - --vsn(?VERSION). - --compile({no_auto_import, [node/0, node/1]}). - -%% Export all functions if test build --ifdef(TEST). - -compile([{no_auto_import, [node/1, node/0]}, export_all]). --else. - -export([ - to_map/1, - to_list/1, - - position/2, - source_location/3, - add_location_data/4, - - declaration/0, - expression/0, - statement/0, - - identifier/1, - literal/1, - program/1, - - spread_element/1, - - variable_declaration/2, - variable_declarator/2, - function_declaration/3, - - this_expression/0, - array_expression/1, - object_expression/1, - property/2, - function_expression/4, - sequence_expression/1, - unary_expression/3, - assignment_expression/3, - binary_expression/3, - update_expression/3, - logical_expression/3, - conditional_expression/3, - new_expression/2, - call_expression/2, - member_expression/3, - arrow_function_expression/6, - yield_expression/1, - generator_expression/3, - comprehension_expression/3, - comprehension_block/3, - comprehension_if/1, - - empty_statement/0, - expression_statement/1, - block_statement/1, - if_statement/3, - labeled_statement/2, - break_statement/1, - continue_statement/1, - with_statement/2, - switch_statement/3, - switch_case/2, - return_statement/1, - throw_statement/1, - try_statement/4, - catch_clause/3, - while_statement/2, - for_statement/4, - for_in_statement/4, - for_of_statement/3, - do_while_statement/2, - debugger_statement/0, - - error/3, - use_strict/0, - const_declaration/2, - var_declaration/2, - let_declaration/2 - ]). --endif. - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - TYPE DEFINITIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Node composition --type es_literal() :: nonempty_string() - | iolist() - | binary() - | 'null' - | 'undefined' - | integer() - | float() - | boolean(). - --type es_identifier() :: nonempty_string() - | binary() - | string() - | iolist(). - --type es_node() :: {'__estree_node', es_node_type(), PropertyFields::es_node_fields()} - | list() - | tuple(). - --type es_ast() :: es_node() - | [{string(), any()}] - | map(). - --type es_node_type() :: atom(). - --type es_node_field() :: {Key::es_literal(), Value::any()}. - --type es_node_fields() :: [es_node_field()]. - -%% Primitives --type tba_node() :: {'__estree_node', '__tba', PropertyFields::es_node_fields()}. - --type identifier_node() :: {'__estree_node', 'Identifier', PropertyFields::es_node_fields()}. - --type source_location_node() :: {'__estree_node', 'SourceLocation', PropertyFields::es_node_fields()}. - --type position_node() :: {'__estree_node', 'Position', PropertyFields::es_node_fields()}. - --type literal_node() :: {'__estree_node', 'Literal', PropertyFields::es_node_fields()}. - --type program_node() :: {'__estree_node', 'Program', PropertyFields::es_node_fields()}. - --type spread_element_node() :: {'__estree_node', 'SpreadElement', PropertyFields::es_node_fields()}. - --type declaration_node() :: {'__estree_node', 'Declaration', PropertyFields::es_node_fields()} - | variable_declaration_node() - | function_declaration_node() - | statement_node(). - --type expression_node() :: {'__estree_node', 'Expression', PropertyFields::es_node_fields()} - | this_expression_node() - | array_expression_node() - | object_expression_node() - | function_expression_node() - | sequence_expression_node() - | unary_expression_node() - | assignment_expression_node() - | binary_expression_node() - | update_expression_node() - | logical_expression_node() - | conditional_expression_node() - | new_expression_node() - | call_expression_node() - | member_expression_node() - | generator_expression_node() - | comprehension_expression_node() - | yield_expression_node() - | arrow_function_expression_node() - | spread_element_node(). - --type statement_node() :: {'__estree_node', 'Statement', PropertyFields::es_node_fields()} - | empty_statement_node() - | expression_statement_node() - | block_statement_node() - | if_statement_node() - | labeled_statement_node() - | break_statement_node() - | continue_statement_node() - | with_statement_node() - | switch_statement_node() - | return_statement_node() - | throw_statement_node() - | try_statement_node() - | while_statement_node() - | for_statement_node() - | for_in_statement_node() - | for_of_statement_node() - | do_while_statement_node() - | debugger_statement_node(). - -%% Declarations --type variable_declaration_node() :: {'__estree_node', 'VariableDeclaration', PropertyFields::es_node_fields()}. - --type variable_declarator_node() :: {'__estree_node', 'VariableDeclarator', PropertyFields::es_node_fields()}. - --type function_declaration_node() :: {'__estree_node', 'FunctionDeclaration', PropertyFields::es_node_fields()}. - -%% Expressions --type this_expression_node() :: {'__estree_node', 'ThisExpression', PropertyFields::es_node_fields()}. - --type array_expression_node() :: {'__estree_node', 'ArrayExpression', PropertyFields::es_node_fields()}. - --type object_expression_node() :: {'__estree_node', 'ObjectExpression', PropertyFields::es_node_fields()}. - --type object_property_node() :: {'__estree_node', 'Property', PropertyFields::es_node_fields()}. - --type function_expression_node() :: {'__estree_node', 'FunctionExpression', PropertyFields::es_node_fields()}. - --type sequence_expression_node() :: {'__estree_node', 'SequenceExpression', PropertyFields::es_node_fields()}. - --type unary_expression_node() :: {'__estree_node', 'UnaryExpression', PropertyFields::es_node_fields()}. - --type assignment_expression_node() :: {'__estree_node', 'AssignmentExpression', PropertyFields::es_node_fields()}. - --type binary_expression_node() :: {'__estree_node', 'BinaryExpression', PropertyFields::es_node_fields()}. - --type update_expression_node() :: {'__estree_node', 'UpdateExpression', PropertyFields::es_node_fields()}. - --type logical_expression_node() :: {'__estree_node', 'LogicalExpression', PropertyFields::es_node_fields()}. - --type conditional_expression_node() :: {'__estree_node', 'ConditionalExpression', PropertyFields::es_node_fields()}. - --type new_expression_node() :: {'__estree_node', 'NewExpression', PropertyFields::es_node_fields()}. - --type call_expression_node() :: {'__estree_node', 'CallExpression', PropertyFields::es_node_fields()}. - --type member_expression_node() :: {'__estree_node', 'MemberExpression', PropertyFields::es_node_fields()}. - --type generator_expression_node() :: {'__estree_node', 'GeneratorExpression', PropertyFields::es_node_fields()}. - --type comprehension_expression_node() :: {'__estree_node', 'ComprehensionExpression', es_node_fields()}. - --type comprehension_if_node() :: {'__estree_node', 'ComprehensionIf', PropertyFields::es_node_fields()}. - --type comprehension_block_node() :: {'__estree_node', 'ComprehensionBlock', PropertyFields::es_node_fields()}. - --type yield_expression_node() :: {'__estree_node', 'YieldExpression', PropertyFields::es_node_fields()}. - --type arrow_function_expression_node() :: {'__estree_node', 'ArrowExpression', PropertyFields::es_node_fields()}. - -%% Statements --type empty_statement_node() :: {'__estree_node', 'EmptyStatement', PropertyFields::es_node_fields()}. - --type expression_statement_node() :: {'__estree_node', 'ExpressionStatement', PropertyFields::es_node_fields()}. - --type block_statement_node() :: {'__estree_node', 'BlockStatement', PropertyFields::es_node_fields()}. - --type if_statement_node() :: {'__estree_node', 'IfStatement', PropertyFields::es_node_fields()}. - --type labeled_statement_node() :: {'__estree_node', 'LabeledStatement', PropertyFields::es_node_fields()}. - --type break_statement_node() :: {'__estree_node', 'BreakStatement', PropertyFields::es_node_fields()}. - --type continue_statement_node() :: {'__estree_node', 'ContinueStatement', PropertyFields::es_node_fields()}. - --type with_statement_node() :: {'__estree_node', 'WithStatement', PropertyFields::es_node_fields()}. - --type switch_statement_node() :: {'__estree_node', 'SwitchStatement', PropertyFields::es_node_fields()}. - --type switch_case_statement_node() :: {'__estree_node', 'SwitchCase', PropertyFields::es_node_fields()}. - --type return_statement_node() :: {'__estree_node', 'ReturnStatement', PropertyFields::es_node_fields()}. - --type throw_statement_node() :: {'__estree_node', 'ThrowStatement', PropertyFields::es_node_fields()}. - --type try_statement_node() :: {'__estree_node', 'TryStatement', PropertyFields::es_node_fields()}. - --type catch_clause_node() :: {'__estree_node', 'CatchClause', PropertyFields::es_node_fields()}. - --type while_statement_node() :: {'__estree_node', 'WhileStatement', PropertyFields::es_node_fields()}. - --type for_statement_node() :: {'__estree_node', 'ForStatement', PropertyFields::es_node_fields()}. - --type for_in_statement_node() :: {'__estree_node', 'ForInStatement', PropertyFields::es_node_fields()}. - --type for_of_statement_node() :: {'__estree_node', 'ForOfStatement', PropertyFields::es_node_fields()}. - --type do_while_statement_node() :: {'__estree_node', 'DoWhileStatement', PropertyFields::es_node_fields()}. - --type debugger_statement_node() :: {'__estree_node', 'DebuggerStatement', PropertyFields::es_node_fields()}. - -%% Export all node types for external use --export_type([ - es_literal/0, - es_identifier/0, - es_node/0, - es_ast/0, - es_node_type/0, - es_node_field/0, - es_node_fields/0, - tba_node/0, - identifier_node/0, - source_location_node/0, - position_node/0, - literal_node/0, - program_node/0, - spread_element_node/0, - declaration_node/0, - expression_node/0, - statement_node/0, - variable_declaration_node/0, - variable_declarator_node/0, - function_declaration_node/0, - this_expression_node/0, - array_expression_node/0, - object_expression_node/0, - object_property_node/0, - function_expression_node/0, - sequence_expression_node/0, - unary_expression_node/0, - assignment_expression_node/0, - binary_expression_node/0, - update_expression_node/0, - logical_expression_node/0, - conditional_expression_node/0, - new_expression_node/0, - call_expression_node/0, - member_expression_node/0, - generator_expression_node/0, - comprehension_expression_node/0, - comprehension_if_node/0, - comprehension_block_node/0, - yield_expression_node/0, - arrow_function_expression_node/0, - empty_statement_node/0, - expression_statement_node/0, - block_statement_node/0, - if_statement_node/0, - labeled_statement_node/0, - break_statement_node/0, - continue_statement_node/0, - with_statement_node/0, - switch_statement_node/0, - switch_case_statement_node/0, - return_statement_node/0, - throw_statement_node/0, - try_statement_node/0, - catch_clause_node/0, - while_statement_node/0, - for_statement_node/0, - for_in_statement_node/0, - for_of_statement_node/0, - do_while_statement_node/0, - debugger_statement_node/0 -]). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - GUARD MACROS ------------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Macros for use in guards in certain places --define(IS_LITERAL(X), - is_list(X) ; is_binary(X) ; X =:= null ; X =:= undefined ; is_integer(X) ; is_float(X) ; is_boolean(X)). - --define(IS_IDENTIFIER(X), - is_list(X) ; is_binary(X)). - --define(IS_UNARY_OPERATOR(X), - X =:= <<"-">> ; X =:= <<"+">> ; X =:= <<"!">> ; X =:= <<"~">> ; - X =:= <<"typeof">> ; X =:= <<"void">> ; X =:= <<"delete">>). - --define(IS_BINARY_OPERATOR(X), - X =:= <<"==">> ; X =:= <<"!=">> ; X =:= <<"===">> ; X =:= <<"!==">> ; - X =:= <<"<">> ; X =:= <<">">> ; X =:= <<"<=">> ; X =:= <<">=">> ; - X =:= <<"<<">> ; X =:= <<">>">> ; X =:= <<">>>">> ; X =:= <<"+">> ; - X =:= <<"-">> ; X =:= <<"*">> ; X =:= <<"/">> ; X =:= <<"%">> ; - X =:= <<"|">> ; X =:= <<"^">> ; X =:= <<"&">> ; X =:= <<"in">> ; - X =:= <<"instanceof">> ; X =:= <<"..">>). - --define(IS_LOGICAL_OPERATOR(X), - X =:= <<"||">> ; X =:= <<"&&">>). - --define(IS_ASSIGNMENT_OPERATOR(X), - X =:= <<"=">> ; X =:= <<"+=">> ; X =:= <<"-=">> ; X =:= <<"*=">> ; - X =:= <<"/=">> ; X =:= <<"%=">> ; X =:= <<"<<=">> ; X =:= <<">>=">> ; - X =:= <<">>>=">> ; X =:= <<"|=">> ; X =:= <<"^=">> ; X =:= <<"&=">>). - --define(IS_UPDATE_OPERATOR(X), - X =:= <<"++">> ; X =:= <<"--">>). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - UTILITY MACROS & FUNCTIONS ----------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Generates a node datastructure which has yet to be given type information. --spec node() -> tba_node(). -node() -> - node('__tba'). - -%% Generates a node data structure of a given type with no additional parameters --spec node(es_identifier() | atom()) -> es_node(). -node(T) -> - node(T, []). - -%% Generates a node data structure of a given type while also setting additional parameters --spec node(es_identifier() | atom(), - es_node_fields()) -> es_node(). -node(T, Fs) when is_atom(T) -> - NewNode = {'__estree_node', T, [{"type", list_to_binary(atom_to_list(T))}]}, - update_record(NewNode, Fs); -node(T, Fs) when is_list(T) -> - node(list_to_atom(T), Fs). - -%% Updates a given node with the given NodeFields --spec update_record(es_node(), - es_node_fields()) -> es_node(). -update_record({_, _, NodeFields}, NewFields) -> - UpdatedNodeFields = merge_node_fields(NodeFields, NewFields), - {_, NodeType} = lists:keyfind("type", 1, UpdatedNodeFields), - {'__estree_node', list_to_atom(binary_to_list(NodeType)), UpdatedNodeFields}. - -%% Merges two node fields --spec merge_node_fields(es_node_fields(), - es_node_fields()) -> es_node_fields(). -merge_node_fields(Old, New) -> - UniqueToOld = lists:filter(fun({K, _V}) -> not lists:keymember(K, 1, New) end, Old), - New ++ UniqueToOld. - -%% Add location data metadata to any node --spec add_location_data(es_node(), - pos_integer(), - non_neg_integer(), - non_neg_integer()) -> es_node(). -add_location_data(Node, LineNumber, ColStart, ColEnd) -> - update_record(Node, [{"loc", source_location(LineNumber, ColStart, ColEnd)}]). - -%% Converts ESTREE nodes into an erlang map --spec to_map(es_node()) -> map(). -to_map({'__estree_node', _, Params}) -> - maps:from_list([{K, to_map(V)} || {K, V} <- Params]); -to_map(L) when is_list(L) -> - [to_map(Li) || Li <- L]; -to_map(T) when is_tuple(T) -> - to_map(tuple_to_list(T)); -to_map(X) -> - %io:format("ESTREE_TO_MAP fail: ~p~n~n", [X]), - X. - --spec to_list(es_node()) -> list(). -to_list({'__estree_node', _, Params}) -> - [{K, to_list(V)} || {K, V} <- Params]; -to_list(L) when is_list(L) -> - [to_list(Li) || Li <- L]; -to_list(T) when is_tuple(T) -> - to_list(tuple_to_list(T)); -to_list(X) -> - %io:format("ESTREE_TO_MAP fail: ~p~n~n", [X]), - X. - -% identify_normalise(N)-> -% {ok, Regex}=re:compile("[^A-Za-z0-9_$]"), -% iolist_to_binary(re:replace(N,Regex,"_$_",[global])). - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - AST PRIMITIVES ----------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Generates an Identifier Node --spec identifier(es_identifier()) -> identifier_node(). -identifier(Name) when ?IS_IDENTIFIER(Name) -> - % node("Identifier", [{"name", identify_normalise(Name)}]). - node("Identifier", [{"name", Name}]). - -%% Generates a SourceLocation node --spec source_location(pos_integer(), - non_neg_integer(), - non_neg_integer()) -> source_location_node(). -source_location(LineNumber, ColStart, ColEnd) -> - %?spec([{LineNumber, integer}, {ColStart, integer}, {ColEnd, integer}]), - node("SourceLocation", [{"source", null}, - {"start", position(LineNumber, ColStart)}, - {"end", position(LineNumber, ColEnd)}]). - -%% Generates a Position node --spec position(pos_integer(), - non_neg_integer()) -> position_node(). -position(Line, Col) -> - %?spec([{Line, integer}, {Col, integer}]), - node("Position", [{"line", Line}, - {"column", Col}]). - -%% Generates a Literal Node --spec literal(es_literal()) -> literal_node(). -literal(Value) when ?IS_LITERAL(Value) -> - node("Literal", [{"value", Value}]). - -%% Generates a Program Node --spec program([statement_node()]) -> program_node(). -program(Statements) -> - %?spec([{Statements, list_of_statement}]), - node("Program", [{"body", Statements}]). - -%% Generates a generic Declaration Node --spec declaration() -> declaration_node(). -declaration() -> - node('Declaration'). - -%% Generate a generic Expression Node --spec expression() -> expression_node(). -expression() -> - node('Expression'). - -%% Generates a generic Statement Node --spec statement() -> statement_node(). -statement() -> - node('Statement'). - -%% SpreadExpression --spec spread_element(identifier_node() | array_expression_node()) -> spread_element_node(). -spread_element(Argument) -> - %?spec([{Argument, [identifier, arrayExpression]}]), - update_record(node(), [{"type", <<"SpreadElement">>}, - {"argument", Argument}]). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - DECLARATION NODES -------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Generates a variable declaration --spec variable_declaration([variable_declarator_node()], - es_literal()) -> variable_declaration_node(). -variable_declaration(Declarations, Kind) -> - %?spec([{Declarations, list_of_variableDeclarator}, {Kind, [variableType]}]), - update_record(declaration(), [{"type", <<"VariableDeclaration">>}, - {"declarations", Declarations}, - {"kind", Kind}]). - -%% Generates a variable declarator --spec variable_declarator(identifier_node(), - expression_node()) -> variable_declarator_node(). -variable_declarator(Identifier, Init) -> - %?spec([{Identifier, identifier}, {Init, expression}]), - node("VariableDeclarator", [{"id", Identifier}, - {"init", Init}]). - -%% Generate a function declaration --spec function_declaration(identifier_node(), - [identifier_node()], - block_statement_node()) -> function_declaration_node(). -function_declaration(Identifier, Params, Body) -> - %?spec([{Identifier, identifier}, {Params, list_of_identifier}, {Body, [expression, blockStatement]}]), - update_record(declaration(), [{"type", <<"FunctionDeclaration">>}, - {"id", Identifier}, - {"params", Params}, - {"body", Body}]). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - EXPRESSION NODES --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Generate a This expression --spec this_expression() -> this_expression_node(). -this_expression() -> - update_record(expression(), [{"type", <<"ThisExpression">>}]). - -%% Generate an Array expression --spec array_expression([expression_node()]) -> array_expression_node(). -array_expression(Elements) -> - update_record(expression(), [{"type", <<"ArrayExpression">>}, - {"elements", Elements}]). - -%% Generate an Object expression --spec object_expression([object_property_node()]) -> object_expression_node(). -object_expression(Properties) -> - update_record(expression(), [{"type", <<"ObjectExpression">>}, - {"properties", Properties}]). - -%% A Literal Property for Object expressions --spec property(literal_node() | identifier_node(), - expression_node()) -> object_property_node(). -property(Key, Value) -> - node("Property", [{"key", Key}, - {"value", Value}, - {"kind", <<"init">>}]). - -%% Generates a Function expression --spec function_expression(identifier_node() | 'null', - [identifier_node()], - block_statement_node(), - boolean()) -> function_expression_node(). -function_expression(Identifier, Params, Body, Expression) -> - update_record(expression(), [{"type", <<"FunctionExpression">>}, - {"id", Identifier}, - {"params", Params}, - {"body", Body}, - {"expression", Expression}]). - -%% Generates an arrow expression --spec arrow_function_expression([identifier_node()], - [expression_node()], - identifier_node() | 'null', - block_statement_node() | expression_node(), - boolean(), - boolean()) -> arrow_function_expression_node(). -arrow_function_expression(Params, Defaults, Rest, Body, IsGenerator, IsExpression) -> - update_record(expression(), [{"type", <<"ArrowFunctionExpression">>}, - {"params", Params}, - {"defaults", Defaults}, - {"rest", Rest}, - {"body", Body}, - {"generator", IsGenerator}, - {"expression", IsExpression}]). - -%% Generate a sequence expression --spec sequence_expression([expression_node()]) -> sequence_expression_node(). -sequence_expression(Expressions) -> - update_record(expression(), [{"type", <<"SequenceExpression">>}, - {"expressions", Expressions}]). - -%% Generate a unary operation expression --spec unary_expression(any(), - boolean(), - expression_node()) -> unary_expression_node(). -unary_expression(Operator, Prefix, Argument) when ?IS_UNARY_OPERATOR(Operator) -> - update_record(expression(), [{"type", <<"UnaryExpression">>}, - {"operator", Operator}, - {"prefix", Prefix}, - {"argument", Argument}]). - -%% Generate an assignment expression --spec assignment_expression(any(), - expression_node(), - expression_node()) -> assignment_expression_node(). -assignment_expression(Operator, Left, Right) -> - update_record(expression(), [{"type", <<"AssignmentExpression">>}, - {"operator", Operator}, - {"left", Left}, - {"right", Right}]). - -%% Generate a binary operation expression --spec binary_expression(any(), - expression_node(), - expression_node()) -> binary_expression_node(). -binary_expression(Operator, Left, Right) when ?IS_BINARY_OPERATOR(Operator) -> - update_record(expression(), [{"type", <<"BinaryExpression">>}, - {"operator", Operator}, - {"left", Left}, - {"right", Right}]). - -%% Generate an update (increment or decrement) operator expression --spec update_expression(any(), - expression_node(), - boolean()) -> update_expression_node(). -update_expression(Operator, Argument, Prefix) when ?IS_UPDATE_OPERATOR(Operator) -> - update_record(expression(), [{"type", <<"UpdateExpression">>}, - {"operator", Operator}, - {"argument", Argument}, - {"prefix", Prefix}]). - -%% Generate a logical operator expression --spec logical_expression(any(), - expression_node(), - expression_node()) -> logical_expression_node(). -logical_expression(Operator, Left, Right) when ?IS_LOGICAL_OPERATOR(Operator) -> - update_record(expression(), [{"type", <<"LogicalExpression">>}, - {"operator", Operator}, - {"left", Left}, - {"right", Right}]). - -%% Generate a conditional expression --spec conditional_expression(expression_node(), - expression_node(), - expression_node()) -> conditional_expression_node(). -conditional_expression(Test, Alternate, Consequent) -> - update_record(expression(), [{"type", <<"ConditionalExpression">>}, - {"test", Test}, - {"alternate", Alternate}, - {"consequent", Consequent}]). - -%% Generate a new expression --spec new_expression(expression_node(), - [expression_node()]) -> new_expression_node(). -new_expression(Callee, Arguments) -> - update_record(expression(), [{"type", <<"NewExpression">>}, - {"callee", Callee}, - {"arguments", Arguments}]). - -%% Generate a call expression --spec call_expression(expression_node(), - [expression_node()]) -> call_expression_node(). -call_expression(Callee, Arguments) -> - update_record(expression(), [{"type", <<"CallExpression">>}, - {"callee", Callee}, - {"arguments", Arguments}]). - -%% Generate a member expression --spec member_expression(expression_node(), - identifier_node() | expression_node(), - boolean()) -> member_expression_node(). -member_expression(Object, Property, Computed) -> - update_record(expression(), [{"type", <<"MemberExpression">>}, - {"object", Object}, - {"property", Property}, - {"computed", Computed}]). - -%% Generate a yield expression --spec yield_expression(expression_node() | 'null') -> yield_expression_node(). -yield_expression(Argument) -> - update_record(expression(), [{"type", <<"YieldExpression">>}, - {"argument", Argument}]). - -%% Generate an array comprehension expression --spec comprehension_expression(expression_node(), - [comprehension_block_node() | comprehension_if_node()], - expression_node() | 'null') -> comprehension_expression_node(). -comprehension_expression(Body, Blocks, Filter) -> - update_record(expression(), [{"type", <<"ComprehensionExpression">>}, - {"body", Body}, - {"blocks", Blocks}, - {"filter", Filter}]). - -%% Generates a comprehension block node --spec comprehension_block(any(), - expression_node(), - boolean()) -> comprehension_block_node(). -comprehension_block(Left, Right, Each) -> - update_record(expression(), [{"type", <<"ComprehensionBlock">>}, - {"left", Left}, - {"right", Right}, - {"each", Each}]). - -%% Generates a comprehension if node --spec comprehension_if(expression_node()) -> comprehension_if_node(). -comprehension_if(Test) -> - update_record(expression(), [{"type", <<"ComprehensionIf">>}, - {"test", Test}]). - -%% Generates a generator expression --spec generator_expression(expression_node(), - [comprehension_block_node() | comprehension_if_node()], - expression_node() | 'null') -> generator_expression_node(). -generator_expression(Body, Blocks, Filter) -> - update_record(expression(), [{"type", <<"GeneratorExpression">>}, - {"body", Body}, - {"blocks", Blocks}, - {"filter", Filter}]). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - STATEMENT NODES ---------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Generates an empty statement node - i.e. an empty semicolon --spec empty_statement() -> empty_statement_node(). -empty_statement() -> - update_record(statement(), [{"type", <<"EmptyStatement">>}]). - -%% Generates an Expression Statement --spec expression_statement(expression_node()) -> expression_statement_node(). -expression_statement(Expression) -> - update_record(statement(), [{"type", <<"ExpressionStatement">>}, - {"expression", Expression}]). - -%% Generates a block statement --spec block_statement([statement_node()]) -> block_statement_node(). -block_statement(Body) -> - update_record(statement(), [{"type", <<"BlockStatement">>}, - {"body", Body}]). - -%% Generates an if statement --spec if_statement(expression_node(), - statement_node(), - statement_node() | 'null') -> if_statement_node(). -if_statement(Test, Consequent, Alternate) -> - update_record(statement(), [{"type", <<"IfStatement">>}, - {"test", Test}, - {"consequent", Consequent}, - {"alternate", Alternate}]). - -%% Generates a Labeled statement (prefixed with break/continue) --spec labeled_statement(identifier_node(), - statement_node()) -> labeled_statement_node(). -labeled_statement(Identifier, Body) -> - update_record(statement(), [{"type", <<"LabeledStatement">>}, - {"label", Identifier}, - {"body", Body}]). - -%% Generates a break statement --spec break_statement(identifier_node() | 'null') -> break_statement_node(). -break_statement(Identifier) -> - update_record(statement(), [{"type", <<"BreakStatement">>}, - {"label", Identifier}]). - -%% Generates a continue statement --spec continue_statement(identifier_node() | 'null') -> continue_statement_node(). -continue_statement(Identifier) -> - update_record(statement(), [{"type", <<"ContinueStatement">>}, - {"label", Identifier}]). - -%% Generates a with statement --spec with_statement(expression_node(), - block_statement_node()) -> with_statement_node(). -with_statement(Expression, BlockStatement) -> - update_record(statement(), [{"type", <<"WithStatement">>}, - {"object", Expression}, - {"body", BlockStatement}]). - -%% Generates a switch statement --spec switch_statement(expression_node(), - [switch_case_statement_node()], - boolean()) -> switch_statement_node(). -switch_statement(Expression, Cases, HasLexScope) -> - update_record(statement(), [{"type", <<"SwitchStatement">>}, - {"discriminant", Expression}, - {"cases", Cases}, - {"lexical", HasLexScope}]). - -%% Generates a case for use in a switch statement --spec switch_case(expression_node(), - [statement_node()]) -> switch_case_statement_node(). -switch_case(Test, Consequent) -> - update_record(statement(), [{"type", <<"SwitchCase">>}, - {"test", Test}, - {"consequent", Consequent}]). - -%% Generates a return statement --spec return_statement(expression_node() | 'null') -> return_statement_node(). -return_statement(Expression) -> - update_record(statement(), [{"type", <<"ReturnStatement">>}, - {"argument", Expression}]). - -%% Generates a throw statement --spec throw_statement(expression_node() | 'null') -> throw_statement_node(). -throw_statement(Expression) -> - update_record(statement(), [{"type", <<"ThrowStatement">>}, - {"argument", Expression}]). - -%% Generates a try statement --spec try_statement(block_statement_node(), - catch_clause_node(), - [catch_clause_node()], - block_statement_node()) -> try_statement_node(). -try_statement(BlockStatement, Handler, GuardedHandler, Finalizer) -> - update_record(statement(), [{"type", <<"TryStatement">>}, - {"block", BlockStatement}, - {"handler", Handler}, - {"guardedHandler", GuardedHandler}, - {"finalizer", Finalizer}]). - -%% Generates a catch clause for use in a try statement --spec catch_clause(identifier_node(), - expression_node(), - block_statement_node()) -> catch_clause_node(). -catch_clause(Param, Guard, Body) -> - update_record(statement(), [{"type", <<"CatchClause">>}, - {"param", Param}, - {"guard", Guard}, - {"body", Body}]). - -%% Generates a while statement --spec while_statement(expression_node(), - statement_node()) -> while_statement_node(). -while_statement(Expression, Body) -> - update_record(statement(), [{"type", <<"WhileStatement">>}, - {"test", Expression}, - {"body", Body}]). - -%% Generates a doWhile statement --spec do_while_statement(expression_node(), - statement_node()) -> do_while_statement_node(). -do_while_statement(Expression, Body) -> - update_record(statement(), [{"type", <<"DoWhileStatement">>}, - {"test", Expression}, - {"body", Body}]). - -%% Generates a for statement --spec for_statement(expression_node() | variable_declaration_node() | 'null', - expression_node() | 'null', - expression_node(), - statement_node()) -> for_statement_node(). -for_statement(Init, Update, Expression, Body) -> - update_record(while_statement(Expression, Body), [{"type", <<"ForStatement">>}, - {"init", Init}, - {"update", Update}]). - -%% Generates a forIn statement --spec for_in_statement(variable_declaration_node() | expression_node(), - expression_node(), - statement_node(), - boolean()) -> for_in_statement_node(). -for_in_statement(Left, Right, Body, Each) -> - update_record(statement(), [{"type", <<"ForInStatement">>}, - {"left", Left}, - {"right", Right}, - {"each", Each}, - {"body", Body}]). - -%% Generates a forOf statement --spec for_of_statement(variable_declaration_node() | expression_node(), - expression_node(), - statement_node()) -> for_of_statement_node(). -for_of_statement(Left, Right, Body) -> - update_record(statement(), [{"type", <<"ForOfStatement">>}, - {"left", Left}, - {"right", Right}, - {"body", Body}]). - -%% Generates a debugger statement --spec debugger_statement() -> debugger_statement_node(). -debugger_statement() -> - update_record(statement(), [{"type", <<"DebuggerStatement">>}]). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - SHORTHANDS FUNCTIONS ----------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Throw an error string --spec error(iolist(), - iolist(), - expression_node()) -> throw_statement_node(). -error(Type, Description, Message) -> - throw_statement( - binary_expression(<<"+">>, - literal(iolist_to_binary(["** ", Type, ": ", Description])), - Message - ) - ). - -%% Use strict directive --spec use_strict() -> expression_statement_node(). -use_strict() -> - expression_statement(literal(<<"use_strict">>)). - -%% Variable declarator variant shorthand --spec const_declaration(es_identifier(), - expression_node()) -> variable_declaration_node(). -const_declaration(Identifier, Init) -> - variable_declaration([variable_declarator(identifier(Identifier), Init)], <<"const">>). - --spec var_declaration(es_identifier(), - expression_node()) -> variable_declaration_node(). -var_declaration(Identifier, Init) -> - variable_declaration([variable_declarator(identifier(Identifier), Init)], <<"var">>). - --spec let_declaration(es_identifier(), - expression_node()) -> variable_declaration_node(). -let_declaration(Identifier, Init) -> - variable_declaration([variable_declarator(identifier(Identifier), Init)], <<"let">>). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - META FUNCTIONS ----------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - --ifdef(TEST). --spec eunit() -> ok. -eunit() -> - eunit:test({inparallel, ?MODULE}), - init:stop(). --endif. diff --git a/doc/corpus/src/jarlang.erl b/doc/corpus/src/jarlang.erl deleted file mode 100644 index 7198cb3..0000000 --- a/doc/corpus/src/jarlang.erl +++ /dev/null @@ -1,385 +0,0 @@ -%%% Module Description: -%%% Main entrypoint into compiler --module(jarlang). --author(["Chris Bailey", "Andrew Johnson"]). - --define(VERSION, "2.1.0"). - --vsn(?VERSION). - -%%% Export all functions if we compiled with erlc -dTEST or c(?MODULE, {d, 'TEST'}). -%%% This is so that we can run external eunit tests --ifdef(TEST). - -compile(export_all). --else. - -export([main/1, - pipeline/1, - pipeline/2, - pipeline/3]). --endif. - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - TYPE DEFINITIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - --type input_args() :: [atom() | string()]. - --type pipeline_stage() :: js - | js_ast - | core - | core_ast - | all. - --type concurrency_mode() :: single_threaded - | multi_threaded. - -%% Export concurrency_mode type since that'll be used in asttrans --export_type([ - concurrency_mode/0 -]). - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - PUBLIC FUNCTIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%%% Define the arguments that this program can take --define(DEFAULT_ARGS, [ - {["-o", "--output"], o_output, singleton, ".", "Sets the output directory for compiled code. " ++ - "If the directory doesn't exist, we will create it."}, - - {["-t", "--type"], o_type, singleton, "js", "Sets the output type, defaults to 'js'. " ++ - "Valid options are 'js', 'js_ast', 'core_ast', 'core' & 'all'."}, - - {["-h", "--help"], o_help, is_set, false, "Displays this help message and exits."}, - - {["-v", "--version"], o_vsn, is_set, false, "Displays current build version."}, - - {["--single-thread"], o_one_thread, is_set, false, "Forces transpilation to only use only one thread/process. " ++ - "Single-threaded error output is also much nicer."} -]). - -%% Main entrypoint into Jarlang, parses given arguments and decides on what to do. --spec main(input_args()) -> ok. -main(Args) -> - % Normalize args to strings if they're atoms, and parse them. - NArgs = [case is_atom(Arg) of true -> atom_to_list(Arg); false -> Arg end || Arg <- Args], - ParsedArgs = pkgargs:parse(NArgs, ?DEFAULT_ARGS), - - % Read ParsedArgs for arguments - ShowHelp = pkgargs:get(o_help, ParsedArgs), - ShowVsn = pkgargs:get(o_vsn, ParsedArgs), - OutDir = pkgargs:get(o_output, ParsedArgs), - Type = list_to_atom(pkgargs:get(o_type, ParsedArgs)), - Files = perform_wildcard_matches(pkgargs:get(default, ParsedArgs)), - ConcMode = case pkgargs:get(o_one_thread, ParsedArgs) of - true -> single_threaded; - false -> multi_threaded - end, - - try branch(ShowHelp, ShowVsn, OutDir, Type, Files, ConcMode) of - _ -> ok - catch - throw:usage -> - usage(), - help(); - throw:help -> - help(); - throw:vsn -> - version(); - throw:{invalid_type, T} -> - io:format("Type '~p' is an invalid output type. Aborting...~n~n", [T]) - end, - - % Clean up and stop - init:stop(). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - ENTRYPOINT CODE ---------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Determines which function to run depending on arguments given. --spec branch(boolean(), - boolean(), - file:filename_all(), - pipeline_stage(), - [file:filename_all(), ...], - concurrency_mode()) -> ok | no_return(). -branch(_Help = false, _Vsn = false, Outdir, all, Files, ConcMode) when (length(Files) > 0) -> - transpile(Files, Outdir, core, ConcMode), - transpile(Files, Outdir, core_ast, ConcMode), - transpile(Files, Outdir, js_ast, ConcMode), - transpile(Files, Outdir, js, ConcMode); -branch(_Help = false, _Vsn = false, Outdir, Type, Files, ConcMode) when (length(Files) > 0) -> - transpile(Files, Outdir, Type, ConcMode); -branch(_Help = true, _Vsn = false, _OutDir, _Type, _Files = [], _ConcMode) -> - throw(help); -branch(_Help = false, _Vsn = true, _OutDir, _Type, _Files = [], _ConcMode) -> - throw(vsn); -branch(_Help, _Vsn, _OutDir, _Type, _Files, _ConcMode) -> - throw(usage). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - COMPILER PIPELINE -------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - - --spec transpile([file:filename_all()], - file:filename_all(), - pipeline_stage(), - concurrency_mode()) -> ok. -%% Convinience function for synchronously transpiling erl files in js files. -%% Also sets up compilation environment by extracting files to a tmp directory. Also cleans this -%% once transpilation is complete. -transpile(Files, Outdir, js, single_threaded) -> - Codegen = pkgutils:pkg_extract_file("codegen.js"), - pkgutils:pkg_extract_dir("node_modules.zip"), - ASTs = [pipeline(js_ast, File, single_threaded) || File <- Files], - [gen_js(Data, Module, Codegen, Outdir) || {Module, Data} <- ASTs], - pkgutils:pkg_clean_tmp_dir(), - ok; - -%% Convinience function for asynchronously transpiling erl files into js files, and synchronously -%% returning after all processes finish. -%% Also sets up compilation environment by extracting files to a tmp directory. Once transpilation -%% finishes, it then cleans up said directory -transpile(Files, Outdir, js, multi_threaded) -> - Codegen = pkgutils:pkg_extract_file("codegen.js"), - pkgutils:pkg_extract_dir("node_modules.zip"), - Pids = [spawn_transpilation_process(File, js_ast, self()) || File <- Files], - - %% Pass transpilated results into codegen.js to get JavaScript which we can write to a file - [ - receive {Pid, {Module, Ast}} -> - gen_js(Ast, Module, Codegen, Outdir) - end - || Pid <- Pids - ], - pkgutils:pkg_clean_tmp_dir(), - ok; - -%% Convinience function to synchronously transpile erl files into core_ast files -transpile(Files, Outdir, Type, single_threaded) -> - ok = is_valid_type(Type), - Processed = [pipeline(Type, File, single_threaded) || File <- Files], - [write_other(io_lib:format("~p", [Data]), Module, Type, Outdir) || {Module, Data} <- Processed], - ok; - -%% Convinience function for asynchronously transpiling erl files into core_ast files, and synchronously -%% returning after all processes finish. -transpile(Files, Outdir, Type, multi_threaded) -> - ok = is_valid_type(Type), - Pids = [spawn_transpilation_process(File, Type, self()) || File <- Files], - - % Write results to file - [ - receive {Pid, {Module, Data}} -> - write_other(io_lib:format("~p", [Data]), Module, Type, Outdir) - end - || Pid <- Pids - ], - ok. - -%% Spawns a process which performs transpilation for any given file. -%% Returns output to the spawning process --spec spawn_transpilation_process(file:filename_all(), - pipeline_stage(), - pid()) -> pid(). -spawn_transpilation_process(File, Type, MainProcess) -> - spawn_link(fun() -> - MainProcess ! {self(), pipeline(Type, File, multi_threaded)} - end). - -%% Shorthand for calling pipeline/3 where the function called is pipeline going as far as -%% the pipeline is currently implemented, assuming concurrency mode is 'single_threaded' --spec pipeline(file:filename_all()) -> {file:filename_all(), any()}. -pipeline(Module) -> - pipeline(js_ast, Module, single_threaded). - -%% Shorthand for calling pipeline/3 where the function called is pipeline going as far as -%% the pipeline is currently implemented, with the specified concurrency mode. --spec pipeline(file:filename_all(), - concurrency_mode()) -> {file:filename_all(), any()}. -pipeline(Module, ConcMode) -> - pipeline(js_ast, Module, ConcMode). - -%% Calls different modules, all of which implement different parts of our compiler pipeline, -%% and returns the result of that stage of the pipeline to the calling function. -%% The first parameter should be an atom representing what stage of the pipeline you would like -%% to run and produce, such as 'core' or 'core_ast' to generate core_erlang or -%% a core_erlang_ast respectively. --spec pipeline(pipeline_stage(), - file:filename_all(), - concurrency_mode()) -> {file:filename_all(), any()}. -pipeline(core, Module, _ConcMode) -> - {ok, _ModuleName, BinaryData} = coregen:to_core_erlang(Module, return), - {Module, BinaryData}; -pipeline(core_ast, Module, _ConcMode) -> - {ok, AST} = coregen:to_core_erlang_ast(Module, return), - {Module, AST}; -pipeline(js_ast, Module, ConcMode) -> - {_Module, AST} = pipeline(core_ast, Module, ConcMode), - {Module, estree:to_list(asttrans:erast_to_esast(AST, ConcMode))}. - -%% Generate JavaScript by writing our JS AST into a file and then calling escodegen() with a few -%% generate which ultimately shells out to node and calls codegen.js --spec gen_js(estree:es_ast(), - file:filename_all(), - file:filename_all(), - file:filename_all()) -> ok | no_return(). -gen_js(AST, File, Codegen, Outdir) -> - EncodedAST = jsone:encode(AST), - - %% We need to write our json into a temp file so that we can easily pass it into codegen.js - %% We'll dump the temp file into the same directory as codegen.js - WorkingDirectory = filename:dirname(Codegen), - Filename = filename:basename(filename:rootname(File)), - TempFile = lists:flatten([WorkingDirectory, "/", Filename, ".json"]), - filepath:write(EncodedAST, TempFile), - - %% Pass json file into escodegen to generate JavaScript - try escodegen(Codegen, File, TempFile) of - Result -> - write_js(Result, Filename, Outdir) - catch - E -> - {err, E} - end. - -%% Does a little processing before shelling out to NodeJS to generate JavaScript from a given JS AST --spec escodegen(file:filename_all(), - file:filename_all(), - file:filename_all()) -> string(). -escodegen(Codegen, OriginalFile, AstFile) -> - % {ok, M} = compile:file(OriginalFile), - - % % Here we generate some metadata to attach to the generated code - % ModuleName = M:module_info(module), - % ModuleAttrs = M:module_info(attributes), - % ModuleMd5 = M:module_info(md5), - - % Metadata = jsone:encode([{module_name, ModuleName}, - % {attributes, ModuleAttrs}]), - - % WorkingDirectory = filename:dirname(Codegen), - % Filename = filename:basename(filename:rootname(OriginalFile)), - % Metafile = lists:flatten([WorkingDirectory, "/", Filename, ".meta"]), - % filepath:write(Metadata, Metafile), - - % % Remove compiled beam file - % file:delete(Filename ++ ".beam"), - - % Finally call escodegen - os:cmd("node " ++ Codegen ++ " " ++ " " ++ AstFile). - -%% Write results of codegen.js to a file --spec write_js(any(), - file:filename_all(), - file:filename_all()) -> ok | no_return(). -write_js(Result, Filename, Outdir) -> - write_file(Result, Filename, "js", Outdir). - --spec write_other(any(), - file:filename_all(), - pipeline_stage(), - file:filename_all()) -> ok | no_return(). -write_other(Data, File, core_ast, Outdir) -> - Filename = filename:basename(filename:rootname(File)), - write_file(Data, Filename, "est", Outdir); -write_other(Data, File, js_ast, Outdir) -> - Filename = filename:basename(filename:rootname(File)), - write_file(Data, Filename, "jst", Outdir); -write_other(Data, File, core, Outdir) -> - Filename = filename:basename(filename:rootname(File)), - write_file(Data, Filename, "core", Outdir). - -%% Write results of codegen.js to a file --spec write_file(any(), - file:filename_all(), - nonempty_string(), - file:filename_all()) -> ok; - (any(), - file:filename_all(), - nonempty_string(), io) -> no_return(). -write_file(Result, Filename, Ext, "io") -> - write_file(Result, Filename, Ext, io); % dirty hack for dialyzer -write_file(Result, Filename, _Ext, io) -> - io:format("==> Result of transpilation for: ~s.erl~n~s~n", [Filename, Result]); -write_file(Result, Filename, Ext, Outdir) -> - filelib:ensure_dir(Outdir), - ok = file:write_file(lists:flatten([Outdir, "/", Filename, ".", Ext]), Result). - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - MISC FUNCTIONS ----------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Displays usage information --spec usage() -> no_return(). -usage() -> - SelfName = pkgutils:pkg_name(), - io:format("Usage: ~s FILEs... [-o ][-t ]~n" ++ - "Compiles the Erlang source files FILEs you specify into JavaScript.~n" ++ - "Or if Type is set will output a file from that point in the pipeline.~n" ++ - "Example: ~s src/*.erl -o js/~n~n", - [SelfName, - SelfName]). - -%% Displays help information --spec help() -> no_return(). -help() -> - io:format("Valid Configuration Parameters:~n" ++ - "~s~n", - [pkgargs:create_help_string(?DEFAULT_ARGS, 1, 55)]). - -%% Displays version information --spec version() -> no_return(). -version() -> - io:format("Current ~s version: v~s~n~n", - [pkgutils:pkg_name(), - ?VERSION]). - -%% Looks through a list of file names and expands any wildcards that may exist. -%% None wildcards will just be added to the accumulator so that we can crash gracefully -%% later on. --spec perform_wildcard_matches([file:filename_all()]) -> [file:filename_all()]. -perform_wildcard_matches([]) -> - []; -perform_wildcard_matches(FileList) -> - lists:foldl(fun(PotentialWildcard, Accumulator) -> - case filelib:wildcard(PotentialWildcard) of - [] -> - Accumulator ++ [PotentialWildcard]; - Matches -> - Accumulator ++ Matches - end - end, [], FileList). - -%% Checks whether a given type is a valid one, and if so, returns ok. -%% Otherwise throws an error. --spec is_valid_type(pipeline_stage()) -> ok. -is_valid_type(js) -> - ok; -is_valid_type(js_ast) -> - ok; -is_valid_type(core) -> - ok; -is_valid_type(core_ast) -> - ok; -is_valid_type(all) -> - ok; -is_valid_type(Type) -> - throw({invalid_type, Type}). \ No newline at end of file diff --git a/doc/corpus/src/module_erlang.js b/doc/corpus/src/module_erlang.js deleted file mode 100644 index e86589e..0000000 --- a/doc/corpus/src/module_erlang.js +++ /dev/null @@ -1,1337 +0,0 @@ -const erlang = function () { - 'use_strict'; - const exports = { - '!': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['!/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['!/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('!' + ('/' + arguments.length)); - }, - '+': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['+/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['+/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('+' + ('/' + arguments.length)); - }, - '-': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['-/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['-/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('-' + ('/' + arguments.length)); - }, - '*': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['*/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['*/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('*' + ('/' + arguments.length)); - }, - '/': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['//2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['//2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('/' + ('/' + arguments.length)); - }, - 'rem': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['rem/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['rem/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('rem' + ('/' + arguments.length)); - }, - 'div': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['div/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['div/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('div' + ('/' + arguments.length)); - }, - '==': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['==/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['==/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('==' + ('/' + arguments.length)); - }, - '/=': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['/=/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['/=/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('/=' + ('/' + arguments.length)); - }, - '<': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions[' jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['=': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['>/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['>/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('>' + ('/' + arguments.length)); - }, - '>=': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['>=/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['>=/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('>=' + ('/' + arguments.length)); - }, - '=:=': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['=:=/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['=:=/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('=:=' + ('/' + arguments.length)); - }, - '=/=': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['=/=/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['=/=/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('=/=' + ('/' + arguments.length)); - }, - 'compare': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['compare/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['compare/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('compare' + ('/' + arguments.length)); - }, - 'match': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['match/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['match/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('match' + ('/' + arguments.length)); - }, - 'or': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['or/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['or/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('or' + ('/' + arguments.length)); - }, - 'and': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['and/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['and/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('and' + ('/' + arguments.length)); - }, - 'not': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['not/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['not/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('not' + ('/' + arguments.length)); - }, - 'xor': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['xor/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['xor/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('xor' + ('/' + arguments.length)); - }, - 'band': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['band/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['band/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('band' + ('/' + arguments.length)); - }, - 'bor': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['bor/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['bor/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('bor' + ('/' + arguments.length)); - }, - 'bxor': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['bxor/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['bxor/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('bxor' + ('/' + arguments.length)); - }, - 'bnot': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['bnot/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['bnot/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('bnot' + ('/' + arguments.length)); - }, - 'module_info': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 0: - if (Process.isProcess(this)) { - return functions['module_info/0'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['module_info/0'].bind(this)(...args); - }); - } - break; - case 1: - if (Process.isProcess(this)) { - return functions['module_info/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['module_info/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('module_info' + ('/' + arguments.length)); - }, - 'atom_to_list': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['atom_to_list/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['atom_to_list/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('atom_to_list' + ('/' + arguments.length)); - }, - 'list_to_atom': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['list_to_atom/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['list_to_atom/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('list_to_atom' + ('/' + arguments.length)); - }, - 'list_to_existing_atom': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['list_to_existing_atom/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['list_to_existing_atom/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('list_to_existing_atom' + ('/' + arguments.length)); - }, - 'is_atom': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_atom/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_atom/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_atom' + ('/' + arguments.length)); - }, - 'is_binary': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_binary/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_binary/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_binary' + ('/' + arguments.length)); - }, - 'is_bitstring': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_bitstring/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_bitstring/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_bitstring' + ('/' + arguments.length)); - }, - 'is_boolean': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_boolean/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_boolean/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_boolean' + ('/' + arguments.length)); - }, - 'is_float': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_float/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_float/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_float' + ('/' + arguments.length)); - }, - 'is_function': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_function/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_function/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_function ' + ('/' + arguments.length)); - }, - 'is_integer': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_integer/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_integer/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_integer' + ('/' + arguments.length)); - }, - 'is_list': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_list/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_list/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_list' + ('/' + arguments.length)); - }, - 'is_map': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_map/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_map/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_map' + ('/' + arguments.length)); - }, - 'is_number': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_number/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_number/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_number' + ('/' + arguments.length)); - }, - 'is_pid': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_pid/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_pid/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_pid' + ('/' + arguments.length)); - }, - 'is_port': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_port/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_port/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_port' + ('/' + arguments.length)); - }, - 'is_reference': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_reference/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_reference/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_reference' + ('/' + arguments.length)); - }, - 'is_tuple': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['is_tuple/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['is_tuple/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('is_tuple' + ('/' + arguments.length)); - }, - 'abs': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['abs/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['abs/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('abs' + ('/' + arguments.length)); - }, - 'ceil': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['ceil/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['ceil/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('ceil' + ('/' + arguments.length)); - }, - 'floor': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['floor/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['floor/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('floor' + ('/' + arguments.length)); - }, - 'trunc': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['trunc/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['trunc/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('trunc' + ('/' + arguments.length)); - }, - 'self': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 0: - if (Process.isProcess(this)) { - return functions['self/0'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['self/0'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('self' + ('/' + arguments.length)); - }, - 'spawn': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['spawn/1'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['spawn/1'].bind(this)(...args); - }); - } - break; - case 2: - if (Process.isProcess(this)) { - return functions['spawn/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['spawn/2'].bind(this)(...args); - }); - } - break; - case 3: - if (Process.isProcess(this)) { - return functions['spawn/3'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['spawn/3'].bind(this)(...args); - }); - } - break; - case 4: - if (Process.isProcess(this)) { - return functions['spawn/4'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['spawn/4'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('spawn' + ('/' + arguments.length)); - }, - 'register': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 2: - if (Process.isProcess(this)) { - return functions['register/2'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['register/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('register' + ('/' + arguments.length)); - }, - 'registered': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 0: - if (Process.isProcess(this)) { - return functions['registered/0'].bind(this)(...args); - } - else { - return jrts.spawn(function () { - return functions['registered/0'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function ' + ('registered' + ('/' + arguments.length)); - }, - }; - - const functions = { - '!/2': function (_cor1, _cor0) { - if (Pid.isPid(_cor1)) { - return _cor1.sendMessage(_cor0); - } - else if (Atom.isAtom(_cor1) && Pid.isPid(jrts.atoms[_cor1.getValue()])) { - return jrts.atoms[_cor1.getValue()].sendMessage(_cor0); - } - throw '** exception error: bad argument in operator !/2 called as ' + _cor1 + ' ! ' + _cor0; - }, - '+/2': function (_cor1, _cor0) { - if ((Int.isInt(_cor1) || Float.isFloat(_cor1)) && (Int.isInt(_cor0) || Float.isFloat(_cor0))) { - return _cor1.add(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator +/2 called as ' + _cor1 + ' + ' + _cor0; - }, - '-/2': function (_cor1, _cor0) { - if ((Int.isInt(_cor1) || Float.isFloat(_cor1)) && (Int.isInt(_cor0) || Float.isFloat(_cor0))) { - return _cor1.subtract(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator -/2 called as ' + _cor1 + ' - ' + _cor0; - }, - '*/2': function (_cor1, _cor0) { - if ((Int.isInt(_cor1) || Float.isFloat(_cor1)) && (Int.isInt(_cor0) || Float.isFloat(_cor0))) { - return _cor1.multiply(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator */2 called as ' + _cor1 + ' * ' + _cor0; - }, - '//2': function (_cor1, _cor0) { - if ((Int.isInt(_cor1) || Float.isFloat(_cor1)) && (Int.isInt(_cor0) || Float.isFloat(_cor0))) { - return _cor1.divide(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator \'/\'/2 called as ' + _cor1 + ' / ' + _cor0; - }, - 'rem/2': function (_cor1, _cor0) { - if (Int.isInt(_cor1) && Int.isInt(_cor0)) { - return _cor1.remainder(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator rem/2 called as ' + _cor1 + ' rem ' + _cor0; - }, - 'div/2': function (_cor1, _cor0) { - if (Int.isInt(_cor1) && Int.isInt(_cor0)) { - return _cor1.intDivide(_cor0); - } - throw '** exception error: an error occurred when evaluating an arithmetic expression in operator div/2 called as ' + _cor1 + ' div ' + _cor0; - }, - '==/2': function (_cor1, _cor0) { - return compare(_cor1, _cor0) == 0; - }, - '/=/2': function (_cor1, _cor0) { - return compare(_cor1, _cor0) != 0; - }, - '/2': function (_cor1, _cor0) { - return compare(_cor1, _cor0) > 0; - }, - '>=/2': function (_cor1, _cor0) { - return compare(_cor1, _cor0) >= 0; - }, - '=:=/2': function (_cor1, _cor0) { - return _cor1 === _cor0; - }, - '=/=/2': function (_cor1, _cor0) { - return _cor1 !== _cor0; - }, - //returns negative if _cor1 evaluates to less than _cor0, returns 0 if they evaluate equal. Magnitude is not representative of anything - 'compare/2': compare, - //returns true or false, contrary to erlang matching behavior - 'match/2': match, - 'or/2': function (_cor1, _cor0) { - return _cor1 || _cor0; - }, - 'and/2': function (_cor1, _cor0) { - return _cor1 && _cor0; - }, - 'not/1': function (_cor0) { - return !_cor0; - }, - 'xor/2': function (_cor1, _cor0) { - return _cor1 && !_cor0 || _cor0 && !_cor1; - }, - 'bor/2': function (_cor1, _cor0) { - return _cor1 | _cor0; - }, - 'band/2': function (_cor1, _cor0) { - return _cor1 & _cor0; - }, - 'bnot/1': function (_cor0) { - return ~_cor0; - }, - 'bxor/2': function (_cor1, _cor0) { - return _cor1 ^ _cor0; - }, - 'module_info/0': function () { - }, - 'module_info/1': function () { - }, - - 'atom_to_binary/2': function (_cor1, _cor0) { - if (Atom.isAtom(_cor1)) { - return new BitString(_cor1.getValue()); - } - throw "bad argument"; - }, - 'atom_to_list/1': function (_cor0) { - if (_cor0 instanceof Atom) { - return new List(_cor0.toString()); - } - throw "bad argument"; - }, - 'binary_to_atom/2': function (_cor1, _cor0) { - let str = new List(..._cor1); - if (BitString.isBinary(_cor1) && List.isString(str)) { - return new Atom(str); - } - throw "bad argument"; - }, - 'binary_to_existing_atom/2': function (_cor1, _cor0) { - let str = new List(..._cor1); - if (BitString.isBinary(_cor1) && List.isString(str) && Atom.exists(str)) { - return new Atom(str); - } - throw "bad argument"; - }, - 'binary_to_float/1': function (_cor0) { - return; - }, - 'binary_to_integer/1': function (_cor0) { - return; - }, - 'binary_to_integer/2': function (_cor1, _cor0) { - return; - }, - 'binary_to_list/1': function (_cor0) { - if (BitString.isBinary(_cor0)) { - return new List(..._cor0); - } - throw "bad argument"; - }, - 'binary_to_list/3': function (_cor2, _cor1, _cor0) { - return; - }, - 'binary_to_term/1': function (_cor0) { - return; - }, - 'binary_to_term/2': function (_cor1, _cor0) { - return; - }, - 'bitstring_to_list/1': function (_cor0) { - if (BitString.isBitString(_cor0)) { - return new List(..._cor0); - } - throw "bad argument"; - }, - 'float_to_binary/1': function (_cor0) { - return; - }, - 'float_to_binary/2': function (_cor1, _cor0) { - return; - }, - 'float_to_list/1': function (_cor0) { - return; - }, - 'float_to_list/2': function (_cor1, _cor0) { - return; - }, - 'fun_to_list/1': function (_cor0) { - return; - }, - 'integer_to_binary/1': function (_cor0) { - return; - }, - 'integer_to_binary/2': function (_cor1, _cor0) { - return; - }, - 'integer_to_list/1': function (_cor0) { - return; - }, - 'integer_to_list/2': function (_cor1, _cor0) { - return; - }, - 'iolist_to_binary/1': function (_cor0) { - return; - }, - 'iolist_to_iovec/1': function (_cor0) { - return; - }, - 'list_to_atom/1': function (_cor0) { - if (_cor0 instanceof List && List.isString(_cor0)) { - return new Atom(_cor0.toString); - } - throw "bad argument"; - }, - 'list_to_binary/1': function (_cor0) { - if (_cor0 instanceof List) { - let tmp = [..._cor0], upper = 1 << 8; - if ([tmp.every((v) => Int.isInt(v) && v.greaterThan(0) && v.lessThan(upper))]) { - return new BitString(...tmp); - } - } - throw "bad argument"; - }, - 'list_to_bitstring/1': function (_cor0) { - if (_cor0 instanceof List) { - let tmp = [..._cor0], upper = 1 << 8; - if ([tmp.every((v) => Int.isInt(v) && v.greaterThan(0) && v.lessThan(upper))]) { - return new BitString(...tmp); - } - } - throw "bad argument"; - }, - 'list_to_existing_atom/1': function (_cor0) { - if (_cor0 instanceof List && List.isString(_cor0) && Atom.exists(_cor0.toString())) { - return new Atom(_cor0.toString); - } - throw "bad argument"; - }, - 'list_to_float/1': function (_cor0) { - return; - }, - 'list_to_integer/1': function (_cor0) { - return; - }, - 'list_to_integer/2': function (_cor1, _cor0) { - return; - }, - 'list_to_pid/1': function (_cor0) { - return; - }, - 'list_to_port/1': function (_cor0) { - return; - }, - 'list_to_ref/1': function (_cor0) { - return; - }, - 'list_to_tuple/1': function (_cor0) { - return; - }, - 'localtime_to_universaltime/1': function (_cor0) { - return; - }, - 'localtime_to_universaltime/2': function (_cor1, _cor0) { - return; - }, - 'pid_to_list/1': function (_cor0) { - return; - }, - 'port_to_list/1': function (_cor0) { - return; - }, - 'ref_to_list/1': function (_cor0) { - return; - }, - 'term_to_binary/1': function (_cor0) { - return; - }, - 'term_to_binary/2': function (_cor1, _cor0) { - return; - }, - 'tuple_to_list/1': function (_cor0) { - return; - }, - 'universaltime_to_localtime/1': function (_cor0) { - return; - }, - - 'is_atom/1': function (_cor0) { - return Atom.isAtom(_cor0); - }, - 'is_binary/1': function (_cor0) { - return BitString.isBinary(_cor0); - }, - 'is_bitstring/1': function (_cor0) { - return BitString.isBitString(_cor0); - }, - 'is_boolean/1': function (_cor0) { - return Atom.isAtom(_cor0) && (_cor0.toString() == "true" || _cor0.toString == "false"); - }, - 'is_float/1': function (_cor0) { - return Float.isFloat(_cor0); - }, - 'is_function/1': function (_cor0) { - return Fun.isFun(_cor0); - }, - 'is_integer/1': function (_cor0) { - return Int.isInt(_cor0); - }, - 'is_list/1': function (_cor0) { - return List.isList(_cor0); - }, - 'is_map/1': function (_cor0) { - return ErlMap.isErlMap(_cor0); - }, - 'is_number/1': function (_cor0) { - return Int.isInt(_cor0) || Float.isFloat(_cor0); - }, - 'is_pid/1': function (_cor0) { - return Pid.isPid(_cor0); - }, - 'is_port/1': function (_cor0) { - return Port.isPort(_cor0); - }, - 'is_reference/1': function (_cor0) { - return Reference.isReference(_cor0); - }, - 'is_tuple/1': function (_cor0) { - return Tuple.isTuple(_cor0); - }, - - 'abs/1': function (_cor0) { - return Int.isInt(_cor0) ? new Int(_cor0.getValue().abs()) : new Float(_cor0.getValue().abs()); - }, - 'ceil/1': function (_cor0) { - return new Int(_cor0.getValue().ceil()); - }, - 'floor/1': function (_cor0) { - return new Int(_cor0.getValue().floor()); - }, - 'trunc/1': function (_cor0) { - return new Int(_cor0.getValue().trunc()); - }, - - 'self/0': function () { - return this.getValue(); - }, - 'spawn/1': function (_cor0) { - return functions["spawn/2"](null, _cor0); - }, - 'spawn/2': function (_cor0, _cor1) { - console.warn("Currently Jarlang processes don't store what module they're currently calling from " + - "and thus, we cannot guarentee that automatically coercing the module without explicityly " + - "specifying it will work.\n Please use spawn/3 or spawn/4 if you can for now."); - return functions["spawn/4"](_cor0, null, _cor1, new List()); - }, - 'spawn/3': function (_cor0, _cor1, _cor2) { - return functions["spawn/4"](null, _cor0, _cor1, _cor2); - }, - 'spawn/4': function (_cor0, _cor1, _cor2, _cor3) { - console.warn("Currently Jarlang doesn't support spawning on different nodes " + - "so this value will be ignored and any new processes will be spawned on the current node."); - - const modulename = _cor1 ? _cor1.toString() : "erlang"; - /* jshint ignore:start */ - const module = eval(modulename); - /* jshint ignore:end */ - - const fnname = `${_cor2.toString()}${module === this ? "/" + _cor3.size() : ""}`; - const fn = module[fnname]; - - if (fn !== undefined) { - return jrts.spawn(function() { - return fn.bind(this)(..._cor3); - }); - } - else { - throw '** exception error: tried to spawn an undefined function ' + modulename + "['" + fnname + "']"; - } - }, - 'register/2': function (_cor0, _cor1) { - if (Atom.isAtom(_cor0) && Pid.isPid(_cor1)) { - _cor0.registerPid(_cor1); - } - else { - throw `** exception error: register/2 expects types (Atom, Pid) but (${_cor0.constructor.name}, ${_cor1.constructor.name}) was given instead.`; - } - }, - 'registered/0': function () { - let buffer = []; - for (let atom in jrts.atoms) { - if (Pid.isPid(jrts.atoms[atom])) { - buffer.push(new Atom(atom)); - } - } - return buffer.length ? new List(...buffer) : new List(); - } - }; - - // Private Methods ----------------------------------------------------------------------------------------------- - - //returns true or false, contrary to erlang matching behavior - function match(_cor1, _cor0) { - if (_cor1 == undefined) { - return true; - } - else if (_cor1 instanceof Int) { - return (_cor0 instanceof Int || _cor0 instanceof Float) && _cor1.equals(_cor0); - } - else if (_cor1 instanceof Float) { - return (_cor0 instanceof Int || _cor0 instanceof Float) && _cor1.equals(_cor0); - } - else if (_cor1 instanceof Atom) { - return _cor0 instanceof Atom && _cor1.value == _cor0.value; - } - else if (_cor1 instanceof Reference) { - throw "Reference is not implemented yet"; - } - else if (_cor1 instanceof Fun) { - throw "Fun is not implemented yet"; - } - else if (_cor1 instanceof Port) { - throw "Port is not implemented yet"; - } - else if (_cor1 instanceof Pid) { - throw "Pid is not implemented yet"; - } - else if (_cor1 instanceof Tuple) { - // Shortcircuit comparison because unequal lengths must mean inequality - if (_cor1.size() != _cor0.size()) { - return false; - } - else { - let len = _cor1.size(); - for (let i = 0; i < len; i++) { - let c = match(_cor1.nth(i), _cor0.nth(i)); - if (c) { - continue; - } - else { - return false; - } - } - return true; - } - } - else if (_cor1 instanceof Map) { - throw "Map is not implemented yet"; - } - else if (_cor1 instanceof List) { - throw "List is not implemented yet"; - } - else if (_cor1 instanceof BitString) { - throw "BitString is not implemented yet"; - } - throw "Tried to match on unrecognized type: " + _cor1.toString(); - } - - //returns negative if _cor1 evaluates to less than _cor0, returns 0 if they evaluate equal. Magnitude is not representative of anything - function compare(_cor1, _cor0) { - if (ErlangDatatype.isErlangDatatype(_cor1) && ErlangDatatype.isErlangDatatype(_cor0)) { - const isNumber_cor1 = Int.isInt(_cor1) || Float.isFloat(_cor1); - const isNumber_cor0 = Int.isInt(_cor0) || Float.isFloat(_cor0); - if (isNumber_cor1 && isNumber_cor0) { - return _cor1.greaterThan(_cor0) ? 1 : - _cor1.lessThan(_cor0) ? -1 : - 0; - } - else { - // Lists are compared element by element regardless of size - if (List.isList(_cor1) && List.isList(_cor0)) { - return (() => { - const _arr1 = [..._cor1]; - const _arr0 = [..._cor0]; - const bound = Math.max(_arr1.length, _arr0.length); - let res = 0; - for (let i = 0; i < bound; i++) { - res = compare(_arr1[i] || 0, _arr0[i] || 0); - if (res !== 0) { - break; - } - } - - return res; - })(); - } - // Tuples are first compared by length, before element by element comparison is used - else if (Tuple.isTuple(_cor1) && Tuple.isTuple(_cor0)) { - const _size1 = _cor1.size(); - const _size0 = _cor0.size(); - return _size1 > _size0 ? 1 : - _size1 < _size0 ? -1 : - (() => { - const _arr1 = [..._cor1]; - const _arr0 = [..._cor0]; - let res = 0; - for (let i = 0; i < _size1; i++) { - res = compare(_arr1[i], _arr0[i]); - if (res !== 0) { - break; - } - } - - return res; - })(); - } - // Maps need to be compared by size, then compared by keys (ascending) then by value - else if (Map.isMap(_cor1) && Map.isMap(_cor0)) { - const _keys1 = Object.keys(_cor1.getValue()); - const _keys0 = Object.keys(_cor0.getValue()); - const _size1 = _keys1.length; - const _size0 = _keys0.length; - return _size1 > _size0 ? 1 : - _size1 < _size0 ? -1 : - (() => { - let res = 0; - for (let i = 0; i < _size1; i++) { - res = compare(_keys1[i], _keys0[i]); - if (res !== 0) { - return res; - } - } - for (i = 0; i < _size1; i++) { - res = compare(_cor1[_keys1[i]], _cor0[_keys0[i]]); - if (res !== 0) { - break; - } - } - return res; - })(); - } - else { - const _comparator1 = _cor1.getComparator(); - const _comparator0 = _cor0.getComparator(); - return _comparator1 > _comparator0 ? 1 : - _comparator1 < _comparator0 ? -1 : - 0; - } - } - } - } - - return exports; -}(); diff --git a/doc/corpus/src/module_io.js b/doc/corpus/src/module_io.js deleted file mode 100644 index db874e6..0000000 --- a/doc/corpus/src/module_io.js +++ /dev/null @@ -1,327 +0,0 @@ -const io = function () { - 'use_strict'; - const exports = { - - 'format': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 1: - if (Process.isProcess(this)) { - return functions['format/1'].bind(this)(...args); - } else { - return jrts.spawn(function() { - return functions['format/1'].bind(this)(...args); - }); - } - break; - case 2: - if (Process.isProcess(this)) { - return functions['format/2'].bind(this)(...args); - } else { - return jrts.spawn(function() { - return functions['format/2'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function' + ('format' + ('/' + arguments.length)); - }, - - 'module_info': function () { - let args = [...arguments].map(arg => jrts.jsToErlang(arg)); - switch (arguments.length) { - case 0: - if (Process.isProcess(this)) { - return functions['module_info/0'].bind(this)(...args); - } else { - return jrts.spawn(function() { - return functions['module_info/0'].bind(this)(...args); - }); - } - break; - case 1: - if (Process.isProcess(this)) { - return functions['module_info/1'].bind(this)(...args); - } else { - return jrts.spawn(function() { - return functions['module_info/1'].bind(this)(...args); - }); - } - } - throw '** exception error: undefined function' + ('module_info' + ('/' + arguments.length)); - } - }; - - const functions = { - 'columns/0': function () { - var cols = 1; - - if (typeof process == "object" && process.stdout) { - cols = process.stdout.columns; - } - - return new Tuple(new Atom("ok"), new Int(cols)); - }, - 'columns/1': function (_cor0) { - return this['columns/0'](); - }, - - 'format/1': function (_cor0) { - console.log(_cor0.toString()); - return new Atom("ok"); - }, - 'format/2': function (_cor1, _cor0) { - console.log(formatErlangString(_cor1, _cor0).toString()); - return new Atom("ok"); - }, - 'format/3': function (_cor2, _cor1, _cor0) { - this['format/2'](_cor1, _cor0); - }, - - 'fread/2': function (_cor1, _cor0) { - }, - 'fread/3': function (_cor2, _cor1, _cor0) { - return this['fread/2'](_cor1, _cor0); - }, - - 'fwrite/1': function (_cor0) { - return this['format/1'](_cor0); - }, - 'fwrite/2': function (_cor1, _cor0) { - return this['format/2'](_cor1, _cor0); - }, - 'fwrite/3': function (_cor2, _cor1, _cor0) { - return this['format/2'](_cor1, _cor0); - }, - - 'get_chars/2': function (_cor1, _cor0) { - }, - 'get_chars/3': function (_cor2, _cor1, _cor0) { - return this['get_chars/2'](_cor1, _cor0); - }, - - 'get_line/1': function (_cor0) { - }, - 'get_line/2': function (_cor1, _cor0) { - return this['get_line/1'](_cor0); - }, - - 'getopts/0': function () { - }, - 'getopts/1': function (_cor0) { - return this['getopts/0'](); - }, - - 'module_info/0': function () { - }, - 'module_info/1': function (_cor0) { - }, - - 'nl/0': function () { - console.log("\n"); - return new Atom("ok"); - }, - 'nl/1': function (_cor0) { - return this['nl/0'](); - }, - - 'parse_erl_exprs/1': function (_cor0) { - }, - 'parse_erl_exprs/2': function (_cor1, _cor0) { - }, - 'parse_erl_exprs/3': function (_cor2, _cor1, _cor0) { - }, - 'parse_erl_exprs/4': function (_cor3, _cor2, _cor1, _cor0) { - }, - - 'parse_erl_form/1': function (_cor0) { - }, - 'parse_erl_form/2': function (_cor1, _cor0) { - }, - 'parse_erl_form/3': function (_cor2, _cor1, _cor0) { - }, - 'parse_erl_form/4': function (_cor3, _cor2, _cor1, _cor0) { - }, - - 'printable_range/0': function () { - }, - - 'put_chars/1': function (_cor0) { - }, - 'put_chars/2': function (_cor1, _cor0) { - return this['put_chars/1'](_cor0); - }, - - 'read/1': function (_cor0) { - }, - 'read/2': function (_cor1, _cor0) { - }, - 'read/3': function (_cor2, _cor1, _cor0) { - }, - 'read/4': function (_cor3, _cor2, _cor1, cor0) { - }, - - 'rows/0': function () { - var rows = 1; - - if (typeof process == "object" && process.stdout) { - rows = process.stdout.rows; - } - - return new Tuple(new Atom("ok"), new Int(rows)); - }, - 'rows/1': function (_cor0) { - return this['rows/0'](); - }, - - 'scan_erl_exprs/1': function (_cor0) { - }, - 'scan_erl_exprs/2': function (_cor1, _cor0) { - }, - 'scan_erl_exprs/3': function (_cor2, _cor1, _cor0) { - }, - 'scan_erl_exprs/4': function (_cor3, _cor2, _cor1, _cor0) { - }, - - 'scan_erl_form/1': function (_cor0) { - }, - 'scan_erl_form/2': function (_cor1, _cor0) { - }, - 'scan_erl_form/3': function (_cor2, _cor1, _cor0) { - }, - 'scan_erl_form/4': function (_cor3, _cor2, _cor1, _cor0) { - }, - - 'setopts/1': function (_cor0) { - }, - 'setopts/2': function (_cor1, _cor0) { - return this['setopts/1'](_cor0); - }, - - 'write/1': function (_cor0) { - }, - 'write/2': function (_cor1, _cor0) { - return this['write/1'](_cor0); - } - }; - - // Private Methods - function formatErlangString(str, data) { - var isErlList = str instanceof List, fstr = ""; - str = isErlList ? str.toString() : str; - data = isErlList ? [...data] : data; - - for (var i = 0; i < str.length; i++) { - var ch = str.charAt(i); - var d = null; - if (ch == "~") { - i++; - let cur = str.charAt(i); - switch (cur) { - case "~": - fstr += "~"; - break; - - - case "c": - fstr += String.fromCharCode(data.shift()); - break; - - - case "g": - case "f": - d = data.shift(); - var isIntOrFloat = (Int.isInt(d) || Float.isFloat(d)); - if (isIntOrFloat) { - var dval = d.getValue().toNumber(); - var flagTestF = (cur === "f"); - var rangeTestG = (dval >= 0.1 && dval < 10000); - var flagTestG = (cur === "g" && rangeTestG); - if (flagTestF || flagTestG) { - fstr += dval.toFixed(6); - break; - } - else { - data.unshift(d); - // fall through to case e - } - } - else { - throw `** format error: type ${d.constructor.name} cannot be coerced into type Float ("~f", [${d}])`; - break; - } - case "e": - d = data.shift(); - var dval = d.getValue().toNumber(); - if (Int.isInt(d) || Float.isFloat(d) || (cur === "g")) { - fstr += dval.toExponential(6); - } - else { - throw `** format error: type ${d.constructor.name} cannot be coerced into type Float ("~f", [${d}])`; - } - break; - - - case "s": - d = data.shift(); - if (List.isList(d) || BitString.isBitString(d)) { - fstr += [...d].map((c) => { - return String.fromCharCode(c.getValue()); - }).join(""); - } - else if (Atom.isAtom(d)) { - fstr += d.getValue(); - } - else { - throw `** format error: type ${d.constructor.name} cannot be coerced into type String ("~s", [${d}])`; - } - break; - - - case "W": - case "w": - case "P": - case "p": - fstr += data.shift().toString(); - break; - - case "#": - case "+": - case "b": - case "x": - case "X": - case "B": - d = data.shift(); - if (Int.isInt(d) || Float.isFloat(d)) { - var dval = d.getValue().toNumber(); - fstr += "#" + Number(dval).toString(16); - } - else { - throw `** format error: type ${d.constructor.name} cannot be coerced into type Base N Number ("~f", [${d}])`; - } - break; - - case "n": - fstr += "\n"; - break; - - - case "i": - data.shift(); - break; - - - default: - throw "** bad argument: unknown flag ~" + cur; - } - } - else { - fstr += ch; - } - } - - //console.log("raw: ", fstr.split("")); - return isErlList ? jrts.jsToErlang(fstr) : fstr; - } - - return exports; -}(); diff --git a/doc/corpus/src/tokdata.erl b/doc/corpus/src/tokdata.erl deleted file mode 100644 index 4b983ec..0000000 --- a/doc/corpus/src/tokdata.erl +++ /dev/null @@ -1,124 +0,0 @@ -%%% Provides a means of extracting token data from a given file. --module(tokdata). --author(["Nick Laine", "Chris Bailey"]). --vsn(1.1). - --export([get_exported_function_map/1]). - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - TYPE DEFINITIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% --type category() :: atom(). - --type symbol() :: atom() - | float() - | integer() - | string(). - --type token() :: {category(), erl_anno:anno(), symbol()} - | {category(), erl_anno:anno()}. - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - PUBLIC FUNCTIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Returns a map of the line numbers of exported functions keyed by function name/arity. -%% Throughout the file, this key is referred to as an "export string" or "definition string". --spec get_exported_function_map(file:filename_all()) -> map(). -get_exported_function_map(Filename) -> - Toks = tokenize_file(Filename), - match_export_lines(Toks, find_exports(Toks), #{}). - - - - - -%%% ---------------------------------------------------------------------------------------------%%% -%%% - PUBLIC FUNCTIONS --------------------------------------------------------------------------%%% -%%% ---------------------------------------------------------------------------------------------%%% - -%% Scans and tokenizes a given erlang file; not dissimilar to coregen code that tokenizes core erlang. -%% todo: add tokenize_erl/tokenize_core functions to lib? --spec tokenize_file(file:filename_all()) -> [token()]. -tokenize_file(Filename) -> - case file:read_file(Filename) of - {ok, Bin} -> - case erl_scan:string(binary_to_list(Bin)) of - {ok, Toks, _} -> - Toks; - {error, _, _} -> - error - end; - {error, _} -> - error - end. - -%% Search file tokens for an export directive, then perform processing. -find_exports([{'-', _} | [{atom, _, export} | [{'(', _} | [{'[', _} | Toks]]]]) -> - process_exports(Toks); -find_exports([_ | Toks]) -> - find_exports(Toks); -find_exports([]) -> - ok. - -%% Returns a list of strings representing exported functions, i.e. the keys in the map of export data. -process_exports(Toks) when is_list(Toks) -> - process_exports(Toks, []). - -process_exports([{atom, _, Name} | [{'/', _} | [{integer, _, Arity} | Toks]]], Exp) -> - process_exports(Toks, [atom_to_list(Name) ++ "/" ++ integer_to_list(Arity) | Exp]); -process_exports([{',', _} | Toks], Exp) -> - process_exports(Toks, Exp); -process_exports([{']', _} | [{')', _} | _Toks]], Exp) -> - lists:reverse(Exp); -process_exports(_, _) -> - badexp. - -%% Searches file tokens for the definitions of exported functions. -%% Maps their line numbers to their corresponding export strings. -match_export_lines([{atom, Line, Name} | [{'(', _} | Toks]], ExpList, ExpMap) -> - {NextToks, DefAtom} = process_export_string(Toks, Name, 0), - {NewList, Found} = match_export_string(DefAtom, ExpList, []), - case Found of - true -> - match_export_lines(NextToks, NewList, maps:put(DefAtom, Line, ExpMap)); - _ -> - match_export_lines(NextToks, NewList, ExpMap) - end; -match_export_lines([_ | Toks], ExpList, ExpMap) -> - match_export_lines(Toks, ExpList, ExpMap); -match_export_lines(_Toks, [], ExpMap) -> - ExpMap; -match_export_lines([], ExpList, ExpMap) -> % Should be unreachable - %io:format("Unfound exports: ~p~n", [ExpList]), - ExpMap. - -%% Processes tokens that are believed to belong to a function definition, and builds a definition string accordingly. -%% todo: Make more thorough, as it can't distinguish a function call from a definition until the closing arg bracket. -process_export_string([{',', _} | Toks], Name, Arity) -> - process_export_string(Toks, Name, Arity + 1); -process_export_string([{')', _} | [{'->', _} | Toks]], Name, Arity) -> - {Toks, atom_to_list(Name) ++ "/" ++ integer_to_list(Arity)}; -process_export_string([{')', _} | Toks], _Name, _Arity) -> - {Toks, notdef}; -process_export_string([_ | Toks], Name, 0) -> - process_export_string(Toks, Name, 1); -process_export_string([_ | Toks], Name, Arity) -> - process_export_string(Toks, Name, Arity). - -%% Checks whether a definition string matches an exported function, and removes it from the list of export strings. -match_export_string(notdef, Exp, []) -> - {Exp, false}; -match_export_string(DefAtom, [DefAtom | Exp], Checked) -> - {Checked ++ Exp, true}; -match_export_string(DefAtom, [E | Exp], Checked) -> - match_export_string(DefAtom, Exp, [E | Checked]); -match_export_string(_DefAtom, [], Checked) -> - {Checked, false}. \ No newline at end of file