diff --git a/build.coffee b/tasks.coffee similarity index 71% rename from build.coffee rename to tasks.coffee index fe390b3c..75d94673 100755 --- a/build.coffee +++ b/tasks.coffee @@ -1,8 +1,9 @@ # Custom build scripts, replacing the Rakefile. To invoke (for example): # -# bin/node_coffee -r build.coffee -- parser +# bin/node_coffee -r tasks.coffee -- parser fs: require 'fs' +coffee: require 'coffee-script' # Run a CoffeeScript through our node/coffee interpreter. run: (args) -> @@ -11,7 +12,7 @@ run: (args) -> # Print the usage message for the build scripts. usage: -> - puts "build.coffee usage goes here..." + puts "tasks.coffee usage goes here..." # Build the CoffeeScript source code -- if you're editing the parser, run # this before you run "build parser". @@ -28,9 +29,20 @@ build_parser: -> fs.open(parser_path, process.O_CREAT | process.O_WRONLY | process.O_TRUNC, parseInt('0755', 8)).addCallback (fd) -> fs.write(fd, js) +# Run the CoffeeScript test suite. +run_tests: -> + process.mixin require 'assert' + fs.readdir('test').addCallback (files) -> + for file in files + fs.cat('test/' + file).addCallback (source) -> + js: coffee.compile source + process.compile js, file + + switch process.ARGV[0] when undefined then usage() when 'compiler' then build_compiler() when 'parser' then build_parser() + when 'test' then run_tests() when 'highlighter' then build_highlighter() when 'underscore' then build_underscore() \ No newline at end of file diff --git a/test/fixtures/execution/test_arguments.coffee b/test/fixtures/execution/test_arguments.coffee deleted file mode 100644 index 8ee45de0..00000000 --- a/test/fixtures/execution/test_arguments.coffee +++ /dev/null @@ -1,37 +0,0 @@ -area: (x, y, x1, y1) -> - (x - x1) * (x - y1) - -x: y: 10 -x1: y1: 20 - -puts area(x, y, x1, y1) is 100 - -puts(area(x, y, - x1, y1) is 100) - -puts(area( - x - y - x1 - y1 -) is 100) - - -# Arguments are turned into arrays. -curried: -> - puts area.apply(this, arguments.concat(20, 20)) is 100 - -curried 10, 10 - - -# Arguments is not a special keyword -- it can be assigned to: -func: -> - arguments: 25 - arguments - -puts func(100) is 25 - - -# Arguments can be accessed as a property. -this.arguments: 10 -puts @arguments is 10 diff --git a/test/fixtures/execution/test_array_comprehension.coffee b/test/fixtures/execution/test_array_comprehension.coffee deleted file mode 100644 index 33fb0ddf..00000000 --- a/test/fixtures/execution/test_array_comprehension.coffee +++ /dev/null @@ -1,48 +0,0 @@ -nums: n * n for n in [1, 2, 3] when n % 2 isnt 0 -results: n * 2 for n in nums - -puts results.join(',') is '2,18' - - -obj: {one: 1, two: 2, three: 3} -names: prop + '!' for prop of obj -odds: prop + '!' for prop, value of obj when value % 2 isnt 0 - -puts names.join(' ') is "one! two! three!" -puts odds.join(' ') is "one! three!" - - -evens: for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0 - num *= -1 - num -= 2 - num * -1 - -puts evens.join(', ') is '4, 6, 8' - - -# Make sure that the "in" operator still works. - -puts 2 in evens - - -# When functions are being defined within the body of a comprehension, make -# sure that their safely wrapped in a closure to preserve local variables. - -obj: {} - -methods: ['one', 'two', 'three'] - -for method in methods - name: method - obj[name]: -> - "I'm " + name - -puts obj.one() is "I'm one" -puts obj.two() is "I'm two" -puts obj.three() is "I'm three" - - -# Steps should work for array comprehensions. - -array: [0..10] -puts num % 2 is 0 for num in array by 2 diff --git a/test/fixtures/generation/each.coffee b/test/fixtures/generation/each.coffee deleted file mode 100644 index 9b76b976..00000000 --- a/test/fixtures/generation/each.coffee +++ /dev/null @@ -1,14 +0,0 @@ -# The cornerstone, an each implementation. -# Handles objects implementing forEach, arrays, and raw objects. -_.each: (obj, iterator, context) -> - index: 0 - try - if obj.forEach - obj.forEach(iterator, context) - else if _.isArray(obj) or _.isArguments(obj) - iterator.call(context, item, i, obj) for item, i in obj - else - iterator.call(context, obj[key], key, obj) for key in _.keys(obj) - catch e - throw e if e isnt breaker - obj \ No newline at end of file diff --git a/test/fixtures/generation/each.tokens b/test/fixtures/generation/each.tokens deleted file mode 100644 index 70d9cff1..00000000 --- a/test/fixtures/generation/each.tokens +++ /dev/null @@ -1 +0,0 @@ -[[:COMMENT, [" The cornerstone, an each implementation.", " Handles objects implementing forEach, arrays, and raw objects."]], ["\n", "\n"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "each"], [:ASSIGN, ":"], [:PARAM_START, "("], [:PARAM, "obj"], [",", ","], [:PARAM, "iterator"], [",", ","], [:PARAM, "context"], [:PARAM_END, ")"], ["->", "->"], [:INDENT, 2], [:IDENTIFIER, "index"], [:ASSIGN, ":"], [:NUMBER, "0"], ["\n", "\n"], [:TRY, "try"], [:INDENT, 2], [:IF, "if"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], [:INDENT, 2], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], [:CALL_START, "("], [:IDENTIFIER, "iterator"], [",", ","], [:IDENTIFIER, "context"], [:CALL_END, ")"], [:OUTDENT, 2], [:ELSE, "else"], [:IF, "if"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArray"], [:CALL_START, "("], [:IDENTIFIER, "obj"], [:CALL_END, ")"], [:OR, "or"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArguments"], [:CALL_START, "("], [:IDENTIFIER, "obj"], [:CALL_END, ")"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], [:CALL_START, "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [",", ","], [:IDENTIFIER, "obj"], [:CALL_END, ")"], [:FOR, "for"], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [:IN, "in"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], [:ELSE, "else"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], [:CALL_START, "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "obj"], [:INDEX_START, "["], [:IDENTIFIER, "key"], [:INDEX_END, "]"], [",", ","], [:IDENTIFIER, "key"], [",", ","], [:IDENTIFIER, "obj"], [:CALL_END, ")"], [:FOR, "for"], [:IDENTIFIER, "key"], [:IN, "in"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "keys"], [:CALL_START, "("], [:IDENTIFIER, "obj"], [:CALL_END, ")"], [:OUTDENT, 2], [:OUTDENT, 2], [:CATCH, "catch"], [:IDENTIFIER, "e"], [:INDENT, 2], [:THROW, "throw"], [:IDENTIFIER, "e"], [:IF, "if"], [:IDENTIFIER, "e"], [:ISNT, "isnt"], [:IDENTIFIER, "breaker"], [:OUTDENT, 2], ["\n", "\n"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], ["\n", "\n"]] \ No newline at end of file diff --git a/test/fixtures/generation/inner_comments.coffee b/test/fixtures/generation/inner_comments.coffee deleted file mode 100644 index 48121ffd..00000000 --- a/test/fixtures/generation/inner_comments.coffee +++ /dev/null @@ -1,15 +0,0 @@ -object: { - a: 1 - # Comments between the elements. - b: 2 - # Like this. - c: 3 -} - -array: [ - 1 - # Comments between the elements. - 2 - # Like this. - 3 -] \ No newline at end of file diff --git a/test/fixtures/generation/inner_comments.js b/test/fixtures/generation/inner_comments.js deleted file mode 100644 index 123b8cea..00000000 --- a/test/fixtures/generation/inner_comments.js +++ /dev/null @@ -1,16 +0,0 @@ -(function(){ - var array, object; - object = { - a: 1, - // Comments between the elements. - b: 2, - // Like this. - c: 3 - }; - array = [1, - // Comments between the elements. - 2, - // Like this. - 3 - ]; -})(); \ No newline at end of file diff --git a/test/fixtures/generation/statements_as_expressions.coffee b/test/fixtures/generation/statements_as_expressions.coffee deleted file mode 100644 index 6f6f8616..00000000 --- a/test/fixtures/generation/statements_as_expressions.coffee +++ /dev/null @@ -1,16 +0,0 @@ -# Everything should be able to be an expression. - -result: while sunny? - go_outside() - -puts(3 + try - nonexistent.no_way -catch error - puts(error) - 3 -) - -func: (x) -> - return throw x - -puts(x * x for x in [1..100]) \ No newline at end of file diff --git a/test/fixtures/generation/whitespace.coffee b/test/fixtures/generation/whitespace.coffee deleted file mode 100644 index 781af19b..00000000 --- a/test/fixtures/generation/whitespace.coffee +++ /dev/null @@ -1,20 +0,0 @@ -# test -f1: (x) -> - x * x - f2: (y) -> - y * x - f3: 3 - -# Parens can close on the proper level. -elements.each((el) -> - el.click((event) -> - el.reset() - el.show() if event.active - ) -) - -# Or, parens can close blocks early. -elements.each((el) -> - el.click((event) -> - el.reset() - el.show() if event.active)) \ No newline at end of file diff --git a/test/test_arguments.coffee b/test/test_arguments.coffee new file mode 100644 index 00000000..7915a980 --- /dev/null +++ b/test/test_arguments.coffee @@ -0,0 +1,34 @@ +area: (x, y, x1, y1) -> + (x - x1) * (x - y1) + +x: y: 10 +x1: y1: 20 + +ok area(x, y, x1, y1) is 100, 'basic arguments' + +ok(area(x, y, + x1, y1) is 100, 'arguments on split lines') + +ok(area( + x + y + x1 + y1 +) is 100, 'newline delimited arguments') + + +curried: -> + ok area.apply(this, arguments.concat(20, 20)) is 100, 'arguments converted into an array' + +curried 10, 10 + + +func: -> + arguments: 25 + arguments + +ok func(100) is 25, 'arguments as a regular identifier' + + +this.arguments: 10 +ok @arguments is 10, 'arguments accessed as a property' diff --git a/test/test_array_comprehension.coffee b/test/test_array_comprehension.coffee new file mode 100644 index 00000000..d7cd2a04 --- /dev/null +++ b/test/test_array_comprehension.coffee @@ -0,0 +1,42 @@ +nums: n * n for n in [1, 2, 3] when n % 2 isnt 0 +results: n * 2 for n in nums + +ok results.join(',') is '2,18', 'basic array comprehension' + + +obj: {one: 1, two: 2, three: 3} +names: prop + '!' for prop of obj +odds: prop + '!' for prop, value of obj when value % 2 isnt 0 + +ok names.join(' ') is "one! two! three!", 'basic object comprehension' +ok odds.join(' ') is "one! three!", 'object comprehension with a filter' + + +evens: for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0 + num *= -1 + num -= 2 + num * -1 + +ok evens.join(', ') is '4, 6, 8', 'multiline array comprehension with filter' + + +ok 2 in evens, 'the in operator still works, standalone' + + +# Ensure that the closure wrapper preserves local variables. +obj: {} + +methods: ['one', 'two', 'three'] + +for method in methods + name: method + obj[name]: -> + "I'm " + name + +ok obj.one() is "I'm one" +ok obj.two() is "I'm two" +ok obj.three() is "I'm three" + + +array: [0..10] +ok(num % 2 is 0 for num in array by 2, 'naked ranges are expanded into arrays') diff --git a/test/fixtures/execution/test_assignment.coffee b/test/test_assignment.coffee similarity index 100% rename from test/fixtures/execution/test_assignment.coffee rename to test/test_assignment.coffee diff --git a/test/fixtures/execution/test_blocks.coffee b/test/test_blocks.coffee similarity index 100% rename from test/fixtures/execution/test_blocks.coffee rename to test/test_blocks.coffee diff --git a/test/fixtures/execution/test_calling_super.coffee b/test/test_calling_super.coffee similarity index 100% rename from test/fixtures/execution/test_calling_super.coffee rename to test/test_calling_super.coffee diff --git a/test/fixtures/execution/test_chained_calls.coffee b/test/test_chained_calls.coffee similarity index 100% rename from test/fixtures/execution/test_chained_calls.coffee rename to test/test_chained_calls.coffee diff --git a/test/fixtures/execution/test_destructuring_assignment.coffee b/test/test_destructuring_assignment.coffee similarity index 100% rename from test/fixtures/execution/test_destructuring_assignment.coffee rename to test/test_destructuring_assignment.coffee diff --git a/test/fixtures/execution/test_everything.coffee b/test/test_everything.coffee similarity index 100% rename from test/fixtures/execution/test_everything.coffee rename to test/test_everything.coffee diff --git a/test/fixtures/execution/test_existence.coffee b/test/test_existence.coffee similarity index 100% rename from test/fixtures/execution/test_existence.coffee rename to test/test_existence.coffee diff --git a/test/fixtures/execution/test_expressions.coffee b/test/test_expressions.coffee similarity index 100% rename from test/fixtures/execution/test_expressions.coffee rename to test/test_expressions.coffee diff --git a/test/fixtures/execution/test_fancy_if_statement.coffee b/test/test_fancy_if_statement.coffee similarity index 100% rename from test/fixtures/execution/test_fancy_if_statement.coffee rename to test/test_fancy_if_statement.coffee diff --git a/test/fixtures/execution/test_functions.coffee b/test/test_functions.coffee similarity index 100% rename from test/fixtures/execution/test_functions.coffee rename to test/test_functions.coffee diff --git a/test/fixtures/execution/test_funky_comments.coffee b/test/test_funky_comments.coffee similarity index 100% rename from test/fixtures/execution/test_funky_comments.coffee rename to test/test_funky_comments.coffee diff --git a/test/test_helper.rb b/test/test_helper.rb deleted file mode 100644 index 2941a191..00000000 --- a/test/test_helper.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'lib/coffee-script' - -class Test::Unit::TestCase - include CoffeeScript -end \ No newline at end of file diff --git a/test/fixtures/execution/test_heredocs.coffee b/test/test_heredocs.coffee similarity index 100% rename from test/fixtures/execution/test_heredocs.coffee rename to test/test_heredocs.coffee diff --git a/test/fixtures/execution/test_lexical_scope.coffee b/test/test_lexical_scope.coffee similarity index 100% rename from test/fixtures/execution/test_lexical_scope.coffee rename to test/test_lexical_scope.coffee diff --git a/test/fixtures/execution/test_literals.coffee b/test/test_literals.coffee similarity index 100% rename from test/fixtures/execution/test_literals.coffee rename to test/test_literals.coffee diff --git a/test/fixtures/execution/test_nested_comprehensions.coffee b/test/test_nested_comprehensions.coffee similarity index 100% rename from test/fixtures/execution/test_nested_comprehensions.coffee rename to test/test_nested_comprehensions.coffee diff --git a/test/fixtures/execution/test_newline_escaping.coffee b/test/test_newline_escaping.coffee similarity index 100% rename from test/fixtures/execution/test_newline_escaping.coffee rename to test/test_newline_escaping.coffee diff --git a/test/fixtures/execution/test_operations.coffee b/test/test_operations.coffee similarity index 100% rename from test/fixtures/execution/test_operations.coffee rename to test/test_operations.coffee diff --git a/test/fixtures/execution/test_range_comprehension.coffee b/test/test_range_comprehension.coffee similarity index 100% rename from test/fixtures/execution/test_range_comprehension.coffee rename to test/test_range_comprehension.coffee diff --git a/test/fixtures/execution/test_ranges_and_slices.coffee b/test/test_ranges_and_slices.coffee similarity index 100% rename from test/fixtures/execution/test_ranges_and_slices.coffee rename to test/test_ranges_and_slices.coffee diff --git a/test/fixtures/execution/test_splats.coffee b/test/test_splats.coffee similarity index 100% rename from test/fixtures/execution/test_splats.coffee rename to test/test_splats.coffee diff --git a/test/fixtures/execution/test_splices.coffee b/test/test_splices.coffee similarity index 100% rename from test/fixtures/execution/test_splices.coffee rename to test/test_splices.coffee diff --git a/test/fixtures/execution/test_switch.coffee b/test/test_switch.coffee similarity index 100% rename from test/fixtures/execution/test_switch.coffee rename to test/test_switch.coffee diff --git a/test/fixtures/execution/test_while.coffee b/test/test_while.coffee similarity index 100% rename from test/fixtures/execution/test_while.coffee rename to test/test_while.coffee diff --git a/test/unit/test_execution.rb b/test/unit/test_execution.rb deleted file mode 100644 index 732acb96..00000000 --- a/test/unit/test_execution.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'test_helper' - -class ExecutionTest < Test::Unit::TestCase - - NO_WARNINGS = "0 error(s), 0 warning(s)" - - SOURCES = [ - 'test/fixtures/execution/*.coffee', - 'examples/beautiful_code/*.coffee', - 'examples/computer_science/*.coffee' - ] - - # This is by far the most important test. It evaluates all of the - # CoffeeScript in test/fixtures/execution, as well as examples/beautiful_code, - # ensuring that all our syntax actually works. - def test_execution_of_coffeescript - (`bin/coffee -r #{SOURCES.join(' ')}`).split("\n").each do |line| - assert line == "true" - end - end - - # Test all of the code examples under Narwhal as well. - def test_execution_with_narwhal - (`bin/coffee -r --narwhal #{SOURCES.join(' ')}`).split("\n").each do |line| - assert line == "true" - end - end - - def test_lintless_tests - no_warnings `bin/coffee -l test/fixtures/*/*.coffee` - end - - def test_lintless_examples - no_warnings `bin/coffee -l examples/*.coffee` - end - - def test_lintless_documentation - no_warnings `bin/coffee -l documentation/coffee/*.coffee` - end - - - private - - def no_warnings(output) - output.split("\n").each {|line| assert line == NO_WARNINGS } - end - -end diff --git a/test/unit/test_lexer.rb b/test/unit/test_lexer.rb deleted file mode 100644 index db72a1a1..00000000 --- a/test/unit/test_lexer.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'test_helper' - -class LexerTest < Test::Unit::TestCase - - def setup - @lex = Lexer.new - end - - def test_lexing_an_empty_string - assert @lex.tokenize("") == [] - end - - def test_lexing_basic_assignment - code = "a: 'one'\nb: [1, 2]" - assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [:ASSIGN, ":"], - [:STRING, "'one'"], ["\n", "\n"], [:IDENTIFIER, "b"], [:ASSIGN, ":"], - ["[", "["], [:NUMBER, "1"], [",", ","], [:NUMBER, "2"], ["]", "]"], - ["\n", "\n"]] - end - - def test_lexing_object_literal - code = "{one : 1}" - assert @lex.tokenize(code) == [["{", "{"], [:IDENTIFIER, "one"], [:ASSIGN, ":"], - [:NUMBER, "1"], ["}", "}"], ["\n", "\n"]] - end - - def test_lexing_function_definition - code = "(x, y) -> x * y" - assert @lex.tokenize(code) == [[:PARAM_START, "("], [:PARAM, "x"], - [",", ","], [:PARAM, "y"], [:PARAM_END, ")"], - ["->", "->"], [:INDENT, 2], [:IDENTIFIER, "x"], ["*", "*"], - [:IDENTIFIER, "y"], [:OUTDENT, 2], ["\n", "\n"]] - end - - def test_lexing_if_statement - code = "clap_your_hands() if happy" - assert @lex.tokenize(code) == [[:IDENTIFIER, "clap_your_hands"], [:CALL_START, "("], - [:CALL_END, ")"], [:IF, "if"], [:IDENTIFIER, "happy"], ["\n", "\n"]] - end - - def test_lexing_comment - code = "a: 1\n# comment\n# on two lines\nb: 2" - assert @lex.tokenize(code) == [[:IDENTIFIER, "a"], [:ASSIGN, ":"], [:NUMBER, "1"], - ["\n", "\n"], [:COMMENT, [" comment", " on two lines"]], ["\n", "\n"], - [:IDENTIFIER, "b"], [:ASSIGN, ":"], [:NUMBER, "2"], ["\n", "\n"]] - end - - def test_lexing_newline_escaper - code = "two: 1 + \\\n\n 1" - assert @lex.tokenize(code) == [[:IDENTIFIER, "two"], [:ASSIGN, ":"], - [:NUMBER, "1"], ["+", "+"], [:NUMBER, "1"], ["\n", "\n"]] - end - - def test_lexing - tokens = @lex.tokenize(File.read('test/fixtures/generation/each.coffee')) - assert tokens.inspect == File.read('test/fixtures/generation/each.tokens') - end - -end diff --git a/test/unit/test_parser.rb b/test/unit/test_parser.rb deleted file mode 100644 index 1a95ae84..00000000 --- a/test/unit/test_parser.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'test_helper' - -class ParserTest < Test::Unit::TestCase - - def setup - @par = Parser.new - end - - def test_parsing_an_empty_string - nodes = @par.parse("") - assert nodes.is_a?(Expressions) - assert nodes.expressions.empty? - end - - def test_parsing_a_basic_assignment - nodes = @par.parse("a: 'one'").expressions - assert nodes.length == 1 - assign = nodes.first - assert assign.is_a?(AssignNode) - assert assign.variable.base == 'a' - end - - def test_parsing_an_object_literal - nodes = @par.parse("{one : 1\ntwo : 2}").expressions - obj = nodes.first.base - assert obj.is_a?(ObjectNode) - assert obj.properties.first.variable.base.value == "one" - assert obj.properties.last.variable.base.value == "two" - end - - def test_parsing_an_function_definition - code = @par.parse("(x, y) -> x * y").expressions.first - assert code.params == ['x', 'y'] - body = code.body.expressions.first - assert body.is_a?(OpNode) - assert body.operator == '*' - end - - def test_parsing_if_statement - the_if = @par.parse("clap_your_hands() if happy").expressions.first - assert the_if.is_a?(IfNode) - assert the_if.condition.base == 'happy' - assert the_if.body.is_a?(CallNode) - assert the_if.body.variable.base == 'clap_your_hands' - end - - def test_parsing_array_comprehension - nodes = @par.parse("i for x, i in [10, 9, 8, 7, 6, 5] when i % 2 is 0").expressions - assert nodes.first.is_a?(ForNode) - assert nodes.first.body.base == 'i' - assert nodes.first.filter.operator == '===' - assert nodes.first.source.base.objects.last.base.value == "5" - end - - def test_parsing_comment - nodes = @par.parse("a: 1\n# comment\nb: 2").expressions - assert nodes[1].is_a?(CommentNode) - end - - def test_parsing_inner_comments - nodes = @par.parse(File.read('test/fixtures/generation/inner_comments.coffee')) - assert nodes.compile == File.read('test/fixtures/generation/inner_comments.js') - end - - def test_parsing - nodes = @par.parse(File.read('test/fixtures/generation/each.coffee')) - assign = nodes.expressions[1] - assert assign.is_a?(AssignNode) - assert assign.variable.base == '_' - assert assign.value.is_a?(CodeNode) - assert assign.value.params == ['obj', 'iterator', 'context'] - end - -end