parent
deac9d4c42
commit
14c0651f1f
@ -1,11 +0,0 @@ |
|||||||
cmake_minimum_required(VERSION 2.8) |
|
||||||
include_directories(../..) |
|
||||||
|
|
||||||
if(MSVC) |
|
||||||
add_compile_options(${cxx11_options} /W3) |
|
||||||
add_definitions(-DUNICODE) |
|
||||||
else() |
|
||||||
add_compile_options(${cxx11_options}) |
|
||||||
endif() |
|
||||||
|
|
||||||
add_executable(culebra main.cc) |
|
@ -1,41 +0,0 @@ |
|||||||
|
|
||||||
syn match culOperator "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?" |
|
||||||
syn match culDecNumber "\<[0-9][0-9_]*" |
|
||||||
syn match culFuncCall "\w\(\w\)*("he=e-1,me=e-1 |
|
||||||
syn match culError ";" |
|
||||||
syn match culError "\s*$" |
|
||||||
syn match culLineComment "\(\/\/\|#\).*" contains=@Spell,javaScriptCommentTodo |
|
||||||
|
|
||||||
syn keyword culFunction fn |
|
||||||
syn keyword culSelf self |
|
||||||
syn keyword culConditional if else |
|
||||||
syn keyword culRepeat while |
|
||||||
syn keyword culReturn return |
|
||||||
syn keyword culDebugger debugger |
|
||||||
syn keyword culBoolean true false |
|
||||||
syn keyword culCommentTodo TODO FIXME XXX TBD contained |
|
||||||
syn keyword culStorage mut |
|
||||||
|
|
||||||
syn region culStringS start=+'+ skip=+\\\\\|\\'+ end=+'\|$+ |
|
||||||
syn region culStringD start=+"+ skip=+\\\\\|\\"+ end=+"\|$+ |
|
||||||
syn region culComment start="/\*" end="\*/" contains=@Spell,javaScriptCommentTodo |
|
||||||
|
|
||||||
hi def link culBoolean Boolean |
|
||||||
hi def link culComment Comment |
|
||||||
hi def link culCommentTodo Todo |
|
||||||
hi def link culConditional Conditional |
|
||||||
hi def link culDecNumber Number |
|
||||||
hi def link culFuncCall Function |
|
||||||
hi def link culFunction Type |
|
||||||
hi def link culLineComment Comment |
|
||||||
hi def link culOperator Operator |
|
||||||
hi def link culRepeat Repeat |
|
||||||
hi def link culReturn Statement |
|
||||||
hi def link culDebugger Debug |
|
||||||
hi def link culSelf Constant |
|
||||||
hi def link culStorage StorageClass |
|
||||||
hi def link culStringD String |
|
||||||
hi def link culStringS String |
|
||||||
hi def link culError Error |
|
||||||
|
|
||||||
let b:current_syntax = "cul" |
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,316 +0,0 @@ |
|||||||
#include "culebra.h" |
|
||||||
#include "linenoise.hpp" |
|
||||||
#include <fstream> |
|
||||||
#include <iomanip> |
|
||||||
#include <iostream> |
|
||||||
#include <vector> |
|
||||||
|
|
||||||
using namespace peg; |
|
||||||
using namespace peg::udl; |
|
||||||
using namespace std; |
|
||||||
|
|
||||||
bool read_file(const char* path, vector<char>& buff) |
|
||||||
{ |
|
||||||
ifstream ifs(path, ios::in|ios::binary); |
|
||||||
if (ifs.fail()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
auto size = static_cast<unsigned int>(ifs.seekg(0, ios::end).tellg()); |
|
||||||
|
|
||||||
if (size > 0) { |
|
||||||
buff.resize(size); |
|
||||||
ifs.seekg(0, ios::beg).read(&buff[0], static_cast<streamsize>(buff.size())); |
|
||||||
} |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
struct CommandLineDebugger |
|
||||||
{ |
|
||||||
void operator()(const Ast& ast, culebra::Environment& env, bool force_to_break) { |
|
||||||
if (quit) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if ((command_ == "n" && env.level <= level_) || |
|
||||||
(command_ == "s") || |
|
||||||
(command_ == "o" && env.level < level_)) { |
|
||||||
force_to_break = true; |
|
||||||
} |
|
||||||
|
|
||||||
if (force_to_break) { |
|
||||||
static auto show_initial_usage = true; |
|
||||||
if (show_initial_usage) { |
|
||||||
show_initial_usage = false; |
|
||||||
usage(); |
|
||||||
} |
|
||||||
|
|
||||||
show_lines(ast); |
|
||||||
|
|
||||||
for (;;) { |
|
||||||
cout << endl << "debug> "; |
|
||||||
|
|
||||||
string s; |
|
||||||
std::getline(cin, s); |
|
||||||
|
|
||||||
istringstream is(s); |
|
||||||
is >> command_; |
|
||||||
|
|
||||||
if (command_ == "h") { |
|
||||||
usage(); |
|
||||||
} else if (command_ == "l") { |
|
||||||
is >> display_lines_; |
|
||||||
show_lines(ast); |
|
||||||
} else if (command_ == "p") { |
|
||||||
string symbol; |
|
||||||
is >> symbol; |
|
||||||
print(ast, env, symbol); |
|
||||||
} else if (command_ == "c") { |
|
||||||
break; |
|
||||||
} else if (command_ == "n") { |
|
||||||
break; |
|
||||||
} else if (command_ == "s") { |
|
||||||
break; |
|
||||||
} else if (command_ == "o") { |
|
||||||
break; |
|
||||||
} else if (command_ == "q") { |
|
||||||
quit = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
level_ = env.level;; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void show_lines(const Ast& ast) { |
|
||||||
prepare_cache(ast.path); |
|
||||||
|
|
||||||
cout << endl << "Break in " << ast.path << ":" << ast.line << endl; |
|
||||||
|
|
||||||
auto count = get_line_count(ast.path); |
|
||||||
|
|
||||||
auto lines_ahead = (size_t)((display_lines_ - .5) / 2); |
|
||||||
auto start = (size_t)max((int)ast.line - (int)lines_ahead, 1); |
|
||||||
auto end = min(start + display_lines_, count); |
|
||||||
|
|
||||||
auto needed_digits = to_string(count).length(); |
|
||||||
|
|
||||||
for (auto l = start; l < end; l++) { |
|
||||||
auto s = get_line(ast.path, l); |
|
||||||
if (l == ast.line) { |
|
||||||
cout << "> "; |
|
||||||
} else { |
|
||||||
cout << " "; |
|
||||||
} |
|
||||||
cout << setw(needed_digits) << l << " " << s << endl; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
shared_ptr<Ast> find_function_node(const Ast& ast) { |
|
||||||
auto node = ast.parent; |
|
||||||
while (node->parent && node->tag != "FUNCTION"_) { |
|
||||||
node = node->parent; |
|
||||||
} |
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
void enum_identifiers(const Ast& ast, set<string>& references) { |
|
||||||
for (auto node: ast.nodes) { |
|
||||||
switch (node->tag) { |
|
||||||
case "IDENTIFIER"_: |
|
||||||
references.insert(node->token); |
|
||||||
break; |
|
||||||
case "FUNCTION"_: |
|
||||||
break; |
|
||||||
default: |
|
||||||
enum_identifiers(*node, references); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void print(const Ast& ast, culebra::Environment& env, const string& symbol) { |
|
||||||
if (symbol.empty()) { |
|
||||||
print_all(ast, env); |
|
||||||
} else if (env.has(symbol)) { |
|
||||||
cout << symbol << ": " << env.get(symbol).str() << endl; |
|
||||||
} else { |
|
||||||
cout << "'" << symbol << "'" << "is not undefined." << endl; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void print_all(const Ast& ast, culebra::Environment& env) { |
|
||||||
auto node = find_function_node(ast); |
|
||||||
set<string> references; |
|
||||||
enum_identifiers(*node, references); |
|
||||||
for (const auto& symbol: references) { |
|
||||||
if (env.has(symbol)) { |
|
||||||
const auto& val = env.get(symbol); |
|
||||||
if (val.type != culebra::Value::Function) { |
|
||||||
cout << symbol << ": " << val.str() << endl; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
size_t get_line_count(const string& path) { |
|
||||||
return sources_[path].size(); |
|
||||||
} |
|
||||||
|
|
||||||
string get_line(const string& path, size_t line) { |
|
||||||
const auto& positions = sources_[path]; |
|
||||||
auto idx = line - 1; |
|
||||||
auto first = idx > 0 ? positions[idx - 1] : 0; |
|
||||||
auto last = positions[idx]; |
|
||||||
auto size = last - first; |
|
||||||
|
|
||||||
string s(size, 0); |
|
||||||
ifstream ifs(path, ios::in | ios::binary); |
|
||||||
ifs.seekg(first, ios::beg).read((char*)s.data(), static_cast<streamsize>(s.size())); |
|
||||||
|
|
||||||
size_t count = 0; |
|
||||||
auto rit = s.rbegin(); |
|
||||||
while (rit != s.rend()) { |
|
||||||
if (*rit == '\n') { |
|
||||||
count++; |
|
||||||
} |
|
||||||
++rit; |
|
||||||
} |
|
||||||
|
|
||||||
s = s.substr(0, s.size() - count); |
|
||||||
|
|
||||||
return s; |
|
||||||
} |
|
||||||
|
|
||||||
void prepare_cache(const string& path) { |
|
||||||
auto it = sources_.find(path); |
|
||||||
if (it == sources_.end()) { |
|
||||||
vector<char> buff; |
|
||||||
read_file(path.c_str(), buff); |
|
||||||
|
|
||||||
auto& positions = sources_[path]; |
|
||||||
|
|
||||||
auto i = 0u; |
|
||||||
for (; i < buff.size(); i++) { |
|
||||||
if (buff[i] == '\n') { |
|
||||||
positions.push_back(i + 1); |
|
||||||
} |
|
||||||
} |
|
||||||
positions.push_back(i); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void usage() { |
|
||||||
cout << "Usage: (c)ontinue, (n)ext, (s)tep in, step (o)out, (p)ring, (l)ist, (q)uit" << endl; |
|
||||||
} |
|
||||||
|
|
||||||
bool quit = false; |
|
||||||
string command_; |
|
||||||
size_t level_ = 0; |
|
||||||
size_t display_lines_ = 4; |
|
||||||
map<string, vector<size_t>> sources_; |
|
||||||
}; |
|
||||||
|
|
||||||
int repl(shared_ptr<culebra::Environment> env, bool print_ast) |
|
||||||
{ |
|
||||||
for (;;) { |
|
||||||
auto line = linenoise::Readline("cul> "); |
|
||||||
|
|
||||||
if (line == "exit" || line == "quit") { |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
if (!line.empty()) { |
|
||||||
vector<string> msgs; |
|
||||||
auto ast = culebra::parse("(repl)", line.data(), line.size(), msgs); |
|
||||||
if (ast) { |
|
||||||
if (print_ast) { |
|
||||||
cout << peg::ast_to_s(ast); |
|
||||||
} |
|
||||||
|
|
||||||
culebra::Value val; |
|
||||||
if (interpret(ast, env, val, msgs)) { |
|
||||||
cout << val << endl; |
|
||||||
linenoise::AddHistory(line.c_str()); |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (const auto& msg : msgs) { |
|
||||||
cout << msg << endl;; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int main(int argc, const char** argv) |
|
||||||
{ |
|
||||||
auto print_ast = false; |
|
||||||
auto shell = false; |
|
||||||
auto debug = false; |
|
||||||
vector<const char*> path_list; |
|
||||||
|
|
||||||
int argi = 1; |
|
||||||
while (argi < argc) { |
|
||||||
auto arg = argv[argi++]; |
|
||||||
if (string("--shell") == arg) { |
|
||||||
shell = true; |
|
||||||
} else if (string("--ast") == arg) { |
|
||||||
print_ast = true; |
|
||||||
} else if (string("--debug") == arg) { |
|
||||||
debug = true; |
|
||||||
} else { |
|
||||||
path_list.push_back(arg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!shell) { |
|
||||||
shell = path_list.empty(); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
auto env = make_shared<culebra::Environment>(); |
|
||||||
setup_built_in_functions(*env); |
|
||||||
|
|
||||||
for (auto path: path_list) { |
|
||||||
vector<char> buff; |
|
||||||
if (!read_file(path, buff)) { |
|
||||||
cerr << "can't open '" << path << "'." << endl; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
vector<string> msgs; |
|
||||||
auto ast = culebra::parse(path, buff.data(), buff.size(), msgs); |
|
||||||
if (ast) { |
|
||||||
if (print_ast) { |
|
||||||
cout << peg::ast_to_s(ast); |
|
||||||
} |
|
||||||
|
|
||||||
culebra::Value val; |
|
||||||
auto dbg = debug ? CommandLineDebugger() : culebra::Debugger(); |
|
||||||
if (interpret(ast, env, val, msgs, dbg)) { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (const auto& msg : msgs) { |
|
||||||
cerr << msg << endl; |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
if (shell) { |
|
||||||
repl(env, print_ast); |
|
||||||
} |
|
||||||
} catch (exception& e) { |
|
||||||
cerr << e.what() << endl; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// vim: et ts=4 sw=4 cin cino={1s ff=unix
|
|
@ -1,17 +0,0 @@ |
|||||||
/* |
|
||||||
* Closure test |
|
||||||
*/ |
|
||||||
|
|
||||||
make_func = fn (mut x) { |
|
||||||
mut n = 100 |
|
||||||
fn () { |
|
||||||
n = n + 1 |
|
||||||
x = x + 1 + n |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
f = make_func(10) |
|
||||||
|
|
||||||
puts("1: { f() }") |
|
||||||
puts("2: { f() }") |
|
||||||
puts("3: { f() }") |
|
@ -1,17 +0,0 @@ |
|||||||
/* |
|
||||||
* Fibonacci |
|
||||||
*/ |
|
||||||
|
|
||||||
fib = fn (x) { |
|
||||||
if x < 2 { |
|
||||||
x |
|
||||||
} else { |
|
||||||
self(x - 2) + self(x -1) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
mut i = 0 |
|
||||||
while i < 30 { |
|
||||||
puts("{i}: {fib(i)}") |
|
||||||
i = i + 1 |
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
/* |
|
||||||
* Fizz Buzz |
|
||||||
*/ |
|
||||||
|
|
||||||
mut i = 1 |
|
||||||
while i < 24 { |
|
||||||
if i % 15 == 0 { |
|
||||||
puts('FizzBuzz') |
|
||||||
} else if i % 5 == 0 { |
|
||||||
puts('Buzz') |
|
||||||
} else if i % 3 == 0 { |
|
||||||
puts('Fizz') |
|
||||||
} else { |
|
||||||
puts(i) |
|
||||||
} |
|
||||||
i = i + 1 |
|
||||||
} |
|
@ -1,248 +0,0 @@ |
|||||||
/* |
|
||||||
* Unit tests |
|
||||||
*/ |
|
||||||
|
|
||||||
test_call = fn () { |
|
||||||
ret = fn(){[1,fn(){[4,5,6]},3]}()[1]()[1] |
|
||||||
assert(ret == 5) |
|
||||||
} |
|
||||||
|
|
||||||
test_return = fn () { |
|
||||||
f = fn (x) { |
|
||||||
if x % 2 { |
|
||||||
return 'odd' |
|
||||||
} |
|
||||||
'even' |
|
||||||
} |
|
||||||
assert(f(3) == 'odd') |
|
||||||
assert(f(4) == 'even') |
|
||||||
|
|
||||||
mut val = 0 |
|
||||||
f2 = fn () { |
|
||||||
val = 1 |
|
||||||
return // comment |
|
||||||
val = 2 |
|
||||||
} |
|
||||||
f2() |
|
||||||
assert(val == 1) |
|
||||||
} |
|
||||||
|
|
||||||
test_nil = fn () { |
|
||||||
assert(nil == nil) |
|
||||||
assert(!(nil != nil)) |
|
||||||
|
|
||||||
a = nil |
|
||||||
assert(a == nil) |
|
||||||
assert(!(a != nil)) |
|
||||||
assert(!(a <= nil)) |
|
||||||
assert(!(a < nil)) |
|
||||||
assert(!(a >= nil)) |
|
||||||
assert(!(a > nil)) |
|
||||||
assert(nil == a) |
|
||||||
assert(!(nil != a)) |
|
||||||
assert(!(nil <= a)) |
|
||||||
assert(!(nil < a)) |
|
||||||
assert(!(nil >= a)) |
|
||||||
assert(!(nil > a)) |
|
||||||
} |
|
||||||
|
|
||||||
test_closure = fn () { |
|
||||||
make_func = fn (mut x) { |
|
||||||
mut n = 100 |
|
||||||
fn () { |
|
||||||
n = n + 1 |
|
||||||
x = x + 1 + n |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
f = make_func(10) |
|
||||||
f() |
|
||||||
f() |
|
||||||
ret = f() |
|
||||||
|
|
||||||
assert(ret == 319) |
|
||||||
} |
|
||||||
|
|
||||||
test_array = fn () { |
|
||||||
a = [1,2,3] |
|
||||||
assert(a.size() == 3) |
|
||||||
|
|
||||||
a.push(4) |
|
||||||
assert(a.size() == 4) |
|
||||||
|
|
||||||
b = [] |
|
||||||
assert(b.size() == 0) |
|
||||||
|
|
||||||
c = [1] |
|
||||||
assert(c.size() == 1) |
|
||||||
|
|
||||||
d = [1,2,3](5, 0) |
|
||||||
assert(d.size() == 5 && d[-1] == 0) |
|
||||||
|
|
||||||
e = [1,2,3](2) |
|
||||||
assert(e.size() == 3 && e[-1] == 3) |
|
||||||
|
|
||||||
f = [1,2,3](5) |
|
||||||
assert(f.size() == 5 && f[-1] == nil) |
|
||||||
} |
|
||||||
|
|
||||||
g_ = 1 |
|
||||||
|
|
||||||
test_function = fn () { |
|
||||||
a = 1 |
|
||||||
make = fn () { |
|
||||||
b = 1 |
|
||||||
fn (c) { |
|
||||||
g_ + a + b + c |
|
||||||
} |
|
||||||
} |
|
||||||
f = make() |
|
||||||
assert(f(1) == 4) |
|
||||||
} |
|
||||||
|
|
||||||
test_object = fn () { |
|
||||||
n = 1 |
|
||||||
o = { |
|
||||||
n: 123, |
|
||||||
s: 'str', |
|
||||||
f1: fn (x) { x + this.n }, |
|
||||||
f2: fn (x) { x + n } |
|
||||||
} |
|
||||||
assert(o.size() == 4) |
|
||||||
assert(o.f1(10) == 133) |
|
||||||
assert(o.f2(10) == 11) |
|
||||||
|
|
||||||
a = {} |
|
||||||
a.b = 1 |
|
||||||
assert(a.a == nil) |
|
||||||
assert(a.b == 1) |
|
||||||
assert(a.size() == 1) |
|
||||||
} |
|
||||||
|
|
||||||
test_object_factory = fn () { |
|
||||||
ctor = fn (init) { |
|
||||||
mut n = init |
|
||||||
|
|
||||||
{ |
|
||||||
add: fn (x) { |
|
||||||
n = n + x |
|
||||||
}, |
|
||||||
sub: fn (x) { |
|
||||||
n = n - x |
|
||||||
}, |
|
||||||
val: fn () { |
|
||||||
n |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
calc = ctor(10) |
|
||||||
|
|
||||||
assert(calc.val() == 10) |
|
||||||
assert(calc.add(1) == 11) |
|
||||||
assert(calc.sub(1) == 10) |
|
||||||
} |
|
||||||
|
|
||||||
test_class = fn () { |
|
||||||
// TODO: support 'prototype' property |
|
||||||
Car = { |
|
||||||
new: fn(miles_per_run) { |
|
||||||
mut total_miles = 0 |
|
||||||
|
|
||||||
{ |
|
||||||
run: fn (times) { |
|
||||||
total_miles = total_miles + miles_per_run * times |
|
||||||
}, |
|
||||||
total: fn () { |
|
||||||
total_miles |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
car = Car.new(5) |
|
||||||
car.run(1) |
|
||||||
car.run(2) |
|
||||||
|
|
||||||
assert(car.total() == 15) |
|
||||||
} |
|
||||||
|
|
||||||
test_sum = fn () { |
|
||||||
mut i = 1 |
|
||||||
mut ret = 0 |
|
||||||
while i <= 10 { |
|
||||||
ret = ret + i |
|
||||||
i = i + 1 |
|
||||||
} |
|
||||||
|
|
||||||
assert(ret == 55) |
|
||||||
} |
|
||||||
|
|
||||||
test_fib = fn () { |
|
||||||
fib = fn (x) { |
|
||||||
if x < 2 { |
|
||||||
x |
|
||||||
} else { |
|
||||||
self(x - 2) + self(x -1) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ret = fib(15) |
|
||||||
|
|
||||||
assert(ret == 610) |
|
||||||
} |
|
||||||
|
|
||||||
test_interpolated_string = fn () { |
|
||||||
hello = "Hello" |
|
||||||
world = "World!" |
|
||||||
ret = "{hello} {world}" |
|
||||||
assert(ret == 'Hello World!') |
|
||||||
} |
|
||||||
|
|
||||||
test_lexical_scope = fn () { |
|
||||||
a = 0 |
|
||||||
{ |
|
||||||
let a = 1; |
|
||||||
assert(a == 1) |
|
||||||
} |
|
||||||
assert(a == 0) |
|
||||||
|
|
||||||
mut b = 0 |
|
||||||
{ |
|
||||||
b = 1; |
|
||||||
assert(b == 1) |
|
||||||
} |
|
||||||
assert(b == 1) |
|
||||||
|
|
||||||
c = 0 |
|
||||||
{ |
|
||||||
let mut c = 0; |
|
||||||
c = 1 |
|
||||||
assert(c == 1) |
|
||||||
} |
|
||||||
assert(c == 0) |
|
||||||
|
|
||||||
obj = { |
|
||||||
name: 'object' |
|
||||||
} |
|
||||||
|
|
||||||
assert(obj.name == 'object') |
|
||||||
} |
|
||||||
|
|
||||||
debugger |
|
||||||
test_call() |
|
||||||
test_return() |
|
||||||
test_closure() |
|
||||||
test_nil() |
|
||||||
test_array() |
|
||||||
test_function() |
|
||||||
test_object() |
|
||||||
test_object_factory() |
|
||||||
test_class() |
|
||||||
debugger |
|
||||||
test_sum() |
|
||||||
test_fib() |
|
||||||
test_interpolated_string() |
|
||||||
test_lexical_scope() |
|
||||||
|
|
||||||
return // end |
|
Loading…
Reference in new issue