From 54ad63f2d35587dfaa7255baf782616c718558bd Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Wed, 9 Sep 2020 13:43:51 -0300 Subject: [PATCH] Implement for in statement --- docs/pages/libraries.md | 11 ++++ lib/basic.nelua | 13 +--- lib/iterators.nelua | 48 ++++++++++++++ lib/sequence.nelua | 2 + lib/vector.nelua | 1 + nelua/analyzer.lua | 114 +++++++++++++++++++-------------- nelua/analyzercontext.lua | 4 +- nelua/astbuilder.lua | 20 +++--- nelua/astdefs.lua | 2 +- nelua/astnode.lua | 4 +- nelua/builtins.lua | 2 +- nelua/cgenerator.lua | 17 ++--- nelua/configer.lua | 2 +- nelua/luagenerator.lua | 6 +- nelua/ppcontext.lua | 2 +- nelua/preprocessor.lua | 2 +- nelua/runner.lua | 2 +- nelua/types.lua | 2 + rockspecs/nelua-dev-1.rockspec | 1 + spec/02-syntaxdefs_spec.lua | 9 --- spec/03-typechecker_spec.lua | 3 +- spec/04-luagenerator_spec.lua | 2 +- spec/tools/assert.lua | 17 ++--- tests/sequence_test.nelua | 26 ++++++++ tests/span_test.nelua | 27 ++++++++ tests/vector_test.nelua | 10 +++ 26 files changed, 231 insertions(+), 118 deletions(-) create mode 100644 lib/iterators.nelua diff --git a/docs/pages/libraries.md b/docs/pages/libraries.md index 10426570..8d23826c 100644 --- a/docs/pages/libraries.md +++ b/docs/pages/libraries.md @@ -39,6 +39,17 @@ Basic library contains common functions. | `_VERSION`{:.language-nelua} | A string of Nelua version. | {: .table.table-bordered.table-striped.table-sm} +## iterators + +Iterators library contains iterator related functions. + +| Variable Name | Description | +|---------------|------| +| `ipairs`{:.language-nelua} | Work with vector, sequence, span and array. | +| `pairs`{:.language-nelua} | Alias to ipairs | +| `next`{:.language-nelua} | Work with vector, sequence, span and array. | +{: .table.table-bordered.table-striped.table-sm} + ## filestream Filestream library contains filestream object, mainly used for `io` library. diff --git a/lib/basic.nelua b/lib/basic.nelua index d7d377da..3cba6e38 100644 --- a/lib/basic.nelua +++ b/lib/basic.nelua @@ -58,18 +58,6 @@ global function assert(cond: auto, msg: auto) end --[[ -global function ipairs() - error('not implemented yet') -end - -global function next() - error('not implemented yet') -end - -global function pairs() - error('not implemented yet') -end - global function load() error('not implemented yet') end @@ -119,6 +107,7 @@ global function select() end ]] +-- pairs/ipairs/next is implemented in iterators.nelua -- tostring/tonumber is implemented in stringview.nelua/string.nelua -- type is implemented in traits.nelua -- require is implemented by the nelua compiler diff --git a/lib/iterators.nelua b/lib/iterators.nelua new file mode 100644 index 00000000..7facbf71 --- /dev/null +++ b/lib/iterators.nelua @@ -0,0 +1,48 @@ +-- Include this file to get the globals "pairs", "ipairs" and "next", +-- to be used with when iterating with "for in". + +-- Concept used to pass containers by reference. +local list_reference_concept = #[concept(function(x) + local reftype + local containertype + if x.type.is_pointer then + reftype = x.type + containertype = reftype.subtype + elseif x.type.is_span or x.type.is_sequence then + reftype = x.type + containertype = reftype + else + containertype = x.type + reftype = types.PointerType(containertype) + end + if containertype.is_contiguous then + return reftype + end +end)]# + +-- Macro that implements the next iterator for lists. +## local function impl_ipairs_next(listtype) + index = index + 1 + if index >= (#list + #[listtype.is_oneindexing and 1 or 0]#) then + return false, 0, #[listtype.subtype]#() + end + return true, index, list[index] +## end + +-- Use with "for in" to iterate lists. +global function ipairs(list: list_reference_concept) + ## local listvaltype = list.type:implict_deref_type() + local function ipairs_next(list: #[list.type]#, index: integer) + ## impl_ipairs_next(listvaltype) + end + return ipairs_next, list, #[listvaltype.is_oneindexing and 0 or -1]# +end + +-- Get the next element from a container. +global function next(list: list_reference_concept, + index: #[optional_concept(integer)]#) + ## impl_ipairs_next(list.type:implict_deref_type()) +end + +-- at the moment pairs only works like ipairs +global pairs: auto = ipairs diff --git a/lib/sequence.nelua b/lib/sequence.nelua index f59309b9..cc4dd19a 100644 --- a/lib/sequence.nelua +++ b/lib/sequence.nelua @@ -9,6 +9,7 @@ -- thus by default there is no need to manually reset the sequence. require 'memory' +require 'iterators' ## local make_generic_sequence = generalize(function(T, Allocator) ## static_assert(traits.is_type(T), "invalid type '%s'", T) @@ -33,6 +34,7 @@ require 'memory' local sequenceT = sequenceT.value sequenceT.is_contiguous = true sequenceT.is_sequence = true + sequenceT.is_oneindexing = true -- used in 'ipairs' sequenceT.subtype = T sequenceT.choose_braces_type = function(nodes) return types.ArrayType(T, #nodes) end ]] diff --git a/lib/vector.nelua b/lib/vector.nelua index 925c19ec..c6494fa4 100644 --- a/lib/vector.nelua +++ b/lib/vector.nelua @@ -8,6 +8,7 @@ -- thus by default there is no need to manually reset the vector. require 'memory' +require 'iterators' ## local make_generic_vector = generalize(function(T, Allocator) ## static_assert(traits.is_type(T), "invalid type '%s'", T) diff --git a/nelua/analyzer.lua b/nelua/analyzer.lua index 1d2a3d20..58f057b2 100644 --- a/nelua/analyzer.lua +++ b/nelua/analyzer.lua @@ -177,10 +177,7 @@ local function visitor_convert(context, parent, parentindex, vartype, valnode, v objsym = objtype.symbol assert(objsym) local n = context.parser.astbuilder.aster - local idnode = n.Id{objsym.name} - local pattr = Attr{foreignsymbol=objsym} - idnode.attr:merge(pattr) - idnode.pattr = pattr + local idnode = n.Id{objsym.name, pattr={forcesymbol=objsym}} local newvalnode = n.Call{{valnode}, n.DotIndex{mtname, idnode}} newvalnode.src = valnode.src newvalnode.pos = valnode.pos @@ -442,13 +439,13 @@ end function visitors.Id(context, node) local name = node[1] local symbol - if not node.attr.foreignsymbol then + if not node.attr.forcesymbol then symbol = context.scope.symbols[name] if not symbol then node:raisef("undeclared symbol '%s'", name) end else - symbol = node.attr.foreignsymbol + symbol = node.attr.forcesymbol end symbol:link_node(node) node.done = symbol @@ -1413,40 +1410,6 @@ function visitors.Repeat(context, node) context:pop_scope() end -function visitors.ForIn(context, node) - local _, inexpnodes, blocknode = node[1], node[2], node[3] - assert(#inexpnodes > 0) - if #inexpnodes > 3 then - node:raisef("`in` statement can have at most 3 arguments") - end - local infuncnode = inexpnodes[1] - local infunctype = infuncnode.attr.type - if infunctype and not (infunctype.is_any or infunctype.is_procedure) then - node:raisef("first argument of `in` statement must be a function, but got type '%s'", - infunctype) - end - context:traverse_nodes(inexpnodes) - - repeat - local scope = context:push_forked_cleaned_scope('loop', node) - --[[ - if itvarnodes then - for i,itvarnode in ipairs(itvarnodes) do - local itsymbol = context:traverse_node(itvarnode) - if infunctype and infunctype.is_procedure then - local fittype = infunctype:get_return_type(i) - itsymbol:add_possible_type(fittype) - end - end - end - ]] - context:traverse_node(blocknode) - - local resolutions_count = scope:resolve() - context:pop_scope() - until resolutions_count == 0 -end - function visitors.ForNum(context, node) local itvarnode, begvalnode, compop, endvalnode, stepvalnode, blocknode = node[1], node[2], node[3], node[4], node[5], node[6] @@ -1550,6 +1513,67 @@ function visitors.ForNum(context, node) end end +function visitors.ForIn(context, node) + local itvarnodes, inexpnodes, blocknode = node[1], node[2], node[3] + assert(#itvarnodes > 0) + assert(#inexpnodes > 0) + if #inexpnodes > 3 then + node:raisef("`in` statement can have at most 3 arguments") + end + + if context.generator == 'lua' then -- lua backend + context:traverse_nodes(inexpnodes) + repeat + local scope = context:push_forked_cleaned_scope('loop', node) + context:traverse_node(blocknode) + local resolutions_count = scope:resolve() + context:pop_scope() + until resolutions_count == 0 + else -- on other backends must implement using while loops + local n = context.parser.astbuilder.aster + + -- build extra nodes for the extra iterating values + local itvardeclnodes = {} + local itvaridnodes = {} + for i=1,#itvarnodes-1 do + local itvarnode = itvarnodes[i+1] + itvardeclnodes[i] = itvarnode + itvaridnodes[i] = n.Id{itvarnode[1], pattr={noinit=true}} + end + + -- replace the for in node with a while loop + local newnode = n.Do{n.Block{{ + n.VarDecl{'local', { + n.IdDecl{'__fornext'}, + n.IdDecl{'__forstate'}, + n.IdDecl{'__forit'} + }, + inexpnodes + }, + n.While{n.Boolean{true}, n.Block{{ + n.VarDecl{'local', tabler.insertvalues({ + n.IdDecl{'__forcont', pattr={noinit=true}} + }, itvardeclnodes)}, + n.Assign{ + tabler.insertvalues({ + n.Id{'__forcont'}, + n.Id{'__forit'} + }, itvaridnodes), { + n.Call{{n.Id{'__forstate'}, n.Id{'__forit'}}, n.Id{'__fornext'}} + } + }, + n.If{{{n.UnaryOp{'not', n.Id{'__forcont'}}, n.Block{{ + n.Break{} + }}}}}, + n.VarDecl{'local', {itvarnodes[1]}, {n.Id{'__forit'}}}, + n.Do{blocknode} + }}} + }}} + node:transform(newnode) + context:traverse_node(newnode) + end +end + function visitors.Break(context, node) if not context.scope:get_parent_of_kind('loop') then node:raisef("`break` statement is not inside a loop") @@ -2127,10 +2151,7 @@ local function override_unary_op(context, node, opname, objnode, objtype) local n = context.parser.astbuilder.aster local objsym = objtype.symbol assert(objsym) - local idnode = n.Id{objsym.name} - local pattr = Attr{foreignsymbol=objsym} - idnode.attr:merge(pattr) - idnode.pattr = pattr + local idnode = n.Id{objsym.name, pattr={forcesymbol=objsym}} local newnode = n.Call{{objnode}, n.DotIndex{mtname, idnode}} node:transform(newnode) context:traverse_node(node) @@ -2227,10 +2248,7 @@ local function override_binary_op(context, node, opname, lnode, rnode, ltype, rt local n = context.parser.astbuilder.aster local objsym = objtype.symbol assert(objsym) - local idnode = n.Id{objsym.name} - local pattr = Attr{foreignsymbol=objsym} - idnode.attr:merge(pattr) - idnode.pattr = pattr + local idnode = n.Id{objsym.name, pattr={forcesymbol=objsym}} local newnode = n.Call{{lnode, rnode}, n.DotIndex{mtname, idnode}} if neg then newnode = n.UnaryOp{'not', newnode} diff --git a/nelua/analyzercontext.lua b/nelua/analyzercontext.lua index 82485525..94195d87 100644 --- a/nelua/analyzercontext.lua +++ b/nelua/analyzercontext.lua @@ -8,7 +8,7 @@ local VisitorContext = require 'nelua.visitorcontext' local AnalyzerContext = class(VisitorContext) -function AnalyzerContext:_init(visitors, parser, ast) +function AnalyzerContext:_init(visitors, parser, ast, generator) VisitorContext._init(self, visitors) self.parser = parser self.rootscope = Scope(self, 'root', ast) @@ -25,6 +25,8 @@ function AnalyzerContext:_init(visitors, parser, ast) self.after_analyze = {} self.after_inferences = {} self.unresolvedcount = 0 + assert(generator) + self.generator = generator end function AnalyzerContext:push_pragmas() diff --git a/nelua/astbuilder.lua b/nelua/astbuilder.lua index c4525ee6..2a7f3edd 100644 --- a/nelua/astbuilder.lua +++ b/nelua/astbuilder.lua @@ -36,23 +36,16 @@ function ASTBuilder:create_value(val, srcnode) node = val elseif traits.is_type(val) then local typedefs = require 'nelua.typedefs' - node = aster.Type{'auto'} - -- inject persistent parsed type - local pattr = Attr({ + node = aster.Type{'auto', pattr={ type = typedefs.primtypes.type, value = val - }) - node.attr:merge(pattr) - node.pattr = pattr + }} elseif traits.is_string(val) then node = aster.String{val} elseif traits.is_symbol(val) then - node = aster.Id{val.name} - local pattr = Attr({ - foreignsymbol = val - }) - node.attr:merge(pattr) - node.pattr = pattr + node = aster.Id{val.name, pattr={ + forcesymbol = val + }} elseif bn.isnumeric(val) then local num = bn.parse(val) local neg = false @@ -97,6 +90,9 @@ function ASTBuilder:register(tag, shape) for k,v in iters.spairs(params) do node[k] = v end + if params.pattr then + node.attr:merge(params.pattr) + end return node end return klass diff --git a/nelua/astdefs.lua b/nelua/astdefs.lua index 78bcdccf..db40ec78 100644 --- a/nelua/astdefs.lua +++ b/nelua/astdefs.lua @@ -184,7 +184,7 @@ astbuilder:register('ForNum', { ntypes.Block, -- block }) astbuilder:register('ForIn', { - stypes.array_of(ntypes.IdDecl):is_optional(), -- iteration vars + stypes.array_of(ntypes.IdDecl), -- iteration vars stypes.array_of(ntypes.Node), -- in exprlist ntypes.Block -- block }) diff --git a/nelua/astnode.lua b/nelua/astnode.lua index d9d15002..4d3257eb 100644 --- a/nelua/astnode.lua +++ b/nelua/astnode.lua @@ -99,7 +99,9 @@ function ASTNode:format_message(category, message, ...) message = stringer.pformat(message, ...) if self.src and self.pos then message = errorer.get_pretty_source_pos_errmsg(self.src, self.pos, message, category) - end + else --luacov:disable + message = category .. ': ' .. message .. '\n' + end --luacov:enable return message end diff --git a/nelua/builtins.lua b/nelua/builtins.lua index 59b150d5..da65d0a8 100644 --- a/nelua/builtins.lua +++ b/nelua/builtins.lua @@ -13,7 +13,7 @@ function builtins.require(context, node) local justloaded = false if not attr.loadedast then - local canloadatruntime = config.generator == 'lua' + local canloadatruntime = context.generator == 'lua' local argnode = node[1][1] if not (argnode and argnode.attr.type and argnode.attr.type.is_stringview and diff --git a/nelua/cgenerator.lua b/nelua/cgenerator.lua index 8f1d759a..e54d565a 100644 --- a/nelua/cgenerator.lua +++ b/nelua/cgenerator.lua @@ -1095,19 +1095,10 @@ function visitors.ForNum(context, node, emitter) context:pop_scope() end ---[[ -function visitors.ForIn(_, node, emitter) - local itvarnodes, inexpnodes, blocknode = node:args() - emitter:add_indent_ln("{") - emitter:inc_indent() - --visit_assignments(context, emitter, itvarnodes, inexpnodes, true) - emitter:add_indent("while(true) {") - emitter:add(blocknode) - emitter:add_indent_ln("}") - emitter:dec_indent() - emitter:add_indent_ln("}") -end -]] +function visitors.ForIn() --luacov:disable + -- this should never happen + error('impossible') +end --luacov:enable function visitors.Break(context, _, emitter) destroy_upscopes_variables(context, emitter, 'loop') diff --git a/nelua/configer.lua b/nelua/configer.lua index bea22776..225213b0 100644 --- a/nelua/configer.lua +++ b/nelua/configer.lua @@ -106,7 +106,7 @@ local function create_parser(args) :count("*"):convert(convert_param, tabler.copy(defconfig.define or {})) argparser:option('-P --pragma', 'Set initial compiler pragma') :count("*"):convert(convert_param, tabler.copy(defconfig.pragma or {})) - argparser:option('-g --generator', "Code generator to use (lua/c)", defconfig.generator) + argparser:option('-g --generator', "Code generator backend to use (lua/c)", defconfig.generator) argparser:option('-p --path', "Set module search path", defconfig.path) argparser:option('-L --add-path', "Add module search path", tabler.copy(defconfig.add_path or {})) :count("*"):convert(convert_add_path) diff --git a/nelua/luagenerator.lua b/nelua/luagenerator.lua index a7fa2fe2..86e239ef 100644 --- a/nelua/luagenerator.lua +++ b/nelua/luagenerator.lua @@ -221,11 +221,7 @@ end function visitors.ForIn(context, node, emitter) local itvars, iterator, block = node:args() context:push_forked_scope('loop', node) - if itvars then - emitter:add_indent("for ", itvars) - else - emitter:add_indent("for _") - end + emitter:add_indent("for ", itvars) emitter:add_ln(' in ', iterator, ' do') emitter:add(block) emitter:add_indent_ln("end") diff --git a/nelua/ppcontext.lua b/nelua/ppcontext.lua index e2ec4bed..be9664df 100644 --- a/nelua/ppcontext.lua +++ b/nelua/ppcontext.lua @@ -1,6 +1,6 @@ local traits = require 'nelua.utils.traits' local class = require 'nelua.utils.class' -local VisitorContext = require 'nelua.analyzercontext' +local VisitorContext = require 'nelua.visitorcontext' local PPContext = class(VisitorContext) diff --git a/nelua/preprocessor.lua b/nelua/preprocessor.lua index 116f54e4..59ff2373 100644 --- a/nelua/preprocessor.lua +++ b/nelua/preprocessor.lua @@ -2,7 +2,7 @@ local traits = require 'nelua.utils.traits' local tabler = require 'nelua.utils.tabler' local types = require 'nelua.types' local typedefs = require 'nelua.typedefs' -local VisitorContext = require 'nelua.analyzercontext' +local VisitorContext = require 'nelua.visitorcontext' local PPContext = require 'nelua.ppcontext' local Emitter = require 'nelua.emitter' local except = require 'nelua.utils.except' diff --git a/nelua/runner.lua b/nelua/runner.lua index c8d10e20..cea0de54 100644 --- a/nelua/runner.lua +++ b/nelua/runner.lua @@ -68,7 +68,7 @@ local function run(argv, redirect) -- analyze the ast -- profiler.start() - local context = AnalyzerContext(analyzer.visitors, parser, ast) + local context = AnalyzerContext(analyzer.visitors, parser, ast, config.generator) except.try(function() context = analyzer.analyze(context) end, function(e) diff --git a/nelua/types.lua b/nelua/types.lua index f5c26074..2414143b 100644 --- a/nelua/types.lua +++ b/nelua/types.lua @@ -82,6 +82,8 @@ Type.shape = shaper.shape { is_stringy = shaper.optional_boolean, -- Whether the type represents a contiguous buffer (e.g. arrays, spans and vector in the lib). is_contiguous = shaper.optional_boolean, + -- Weather the type uses 1-based indexing (e.g. sequence and table). + is_oneindexing = shaper.optional_boolean, -- Whether the type is a compile time type (e.g concepts, generics) is_comptime = shaper.optional_boolean, -- Whether the type is used as a polymorphic argument in poly functions. diff --git a/rockspecs/nelua-dev-1.rockspec b/rockspecs/nelua-dev-1.rockspec index 0e4c395b..6b380ccd 100644 --- a/rockspecs/nelua-dev-1.rockspec +++ b/rockspecs/nelua-dev-1.rockspec @@ -125,6 +125,7 @@ build = { ['lib/arg.nelua'] = 'lib/arg.nelua', ['lib/basic.nelua'] = 'lib/basic.nelua', ['lib/io.nelua'] = 'lib/io.nelua', + ['lib/iterators.nelua'] = 'lib/iterators.nelua', ['lib/math.nelua'] = 'lib/math.nelua', ['lib/memory.nelua'] = 'lib/memory.nelua', ['lib/sequence.nelua'] = 'lib/sequence.nelua', diff --git a/spec/02-syntaxdefs_spec.lua b/spec/02-syntaxdefs_spec.lua index f41ce043..87897255 100644 --- a/spec/02-syntaxdefs_spec.lua +++ b/spec/02-syntaxdefs_spec.lua @@ -810,15 +810,6 @@ describe("statement for", function() n.Block{{}}} }}) end) - it("in with no variables", function() - assert.parse_ast(nelua_parser, "in a,b,c do end", - n.Block{{ - n.ForIn{ - nil, - { n.Id{'a'}, n.Id{'b'}, n.Id{'c'} }, - n.Block{{}}} - }}) - end) end) -------------------------------------------------------------------------------- diff --git a/spec/03-typechecker_spec.lua b/spec/03-typechecker_spec.lua index d77c8b7c..f66e42be 100644 --- a/spec/03-typechecker_spec.lua +++ b/spec/03-typechecker_spec.lua @@ -816,10 +816,9 @@ end) it("for in", function() assert.analyze_ast([[local a,b,c; for i in a,b,c do end]]) - assert.analyze_ast([[local a,b,c; in a,b,c do end]]) assert.analyze_error( [[local a = 1; for i in a do end]], - "first argument of `in` statement must be a function") + "cannot call type") assert.analyze_error( [[for i in a,b,c,d do end]], "`in` statement can have at most") diff --git a/spec/04-luagenerator_spec.lua b/spec/04-luagenerator_spec.lua index 2113e82e..c5143cda 100644 --- a/spec/04-luagenerator_spec.lua +++ b/spec/04-luagenerator_spec.lua @@ -113,7 +113,7 @@ it("for", function() assert.generate_lua("for i=1,10,2 do\nend") assert.generate_lua("local a, f\nfor i in a, f() do\nend") assert.generate_lua("local f\nfor i, j, k in f() do\nend") - assert.generate_lua("local f\nin f() do\nend", "local f\nfor _ in f() do\nend") + assert.generate_lua("local f\nfor _ in f() do\nend", "local f\nfor _ in f() do\nend") end) it("break", function() assert.generate_lua("while true do\n break\nend") diff --git a/spec/tools/assert.lua b/spec/tools/assert.lua index 2cc75fb0..1f20c9d0 100644 --- a/spec/tools/assert.lua +++ b/spec/tools/assert.lua @@ -182,7 +182,7 @@ end function assert.generate_lua(nelua_code, expected_code) expected_code = expected_code or nelua_code - local ast, context = assert.analyze_ast(nelua_code) + local ast, context = assert.analyze_ast(nelua_code, nil, 'lua') local generated_code pretty_input_onerror(nelua_code, function() generated_code = assert(lua_generator.generate(ast, context)) @@ -191,7 +191,7 @@ function assert.generate_lua(nelua_code, expected_code) end function assert.generate_c(nelua_code, expected_code, ispattern) - local ast, context = assert.analyze_ast(nelua_code) + local ast, context = assert.analyze_ast(nelua_code, nil, 'c') local generated_code pretty_input_onerror(nelua_code, function() generated_code = assert(c_generator.generate(ast, context)) @@ -220,7 +220,7 @@ function assert.run_error_c(nelua_code, output) end function assert.lua_gencode_equals(code, expected_code) - local ast, context = assert.analyze_ast(code) + local ast, context = assert.analyze_ast(code, nil, 'lua') local expected_ast, expected_context = assert.analyze_ast(expected_code) local generated_code = assert(lua_generator.generate(ast, context)) local expected_generated_code = assert(lua_generator.generate(expected_ast, expected_context)) @@ -228,16 +228,17 @@ function assert.lua_gencode_equals(code, expected_code) end function assert.c_gencode_equals(code, expected_code) - local ast, context = assert.analyze_ast(code) - local expected_ast, expected_context = assert.analyze_ast(expected_code) + local ast, context = assert.analyze_ast(code, nil, 'c') + local expected_ast, expected_context = assert.analyze_ast(expected_code, nil, 'c') local generated_code = assert(c_generator.generate(ast, context)) local expected_generated_code = assert(c_generator.generate(expected_ast, expected_context)) assert.same_string(expected_generated_code, generated_code) end -function assert.analyze_ast(code, expected_ast) +function assert.analyze_ast(code, expected_ast, generator) local ast = assert.parse_ast(nelua_parser, code) - local context = AnalyzerContext(analyzer.visitors, nelua_parser, ast) + generator = generator or config.generator + local context = AnalyzerContext(analyzer.visitors, nelua_parser, ast, generator) pretty_input_onerror(code, function() analyzer.analyze(context) end) @@ -280,7 +281,7 @@ end function assert.analyze_error(code, expected_error) local ast = assert.parse_ast(nelua_parser, code) local ok, e = except.try(function() - local context = AnalyzerContext(analyzer.visitors, nelua_parser, ast) + local context = AnalyzerContext(analyzer.visitors, nelua_parser, ast, config.generator) analyzer.analyze(context) end) pretty_input_onerror(code, function() diff --git a/tests/sequence_test.nelua b/tests/sequence_test.nelua index 9f8a77c5..cf1be752 100644 --- a/tests/sequence_test.nelua +++ b/tests/sequence_test.nelua @@ -134,6 +134,32 @@ do -- passing by reference seqa:destroy() end +do -- ipairs + local seq: sequence(number) = {1,2,3,4} + do -- ipairs + local sum = 0.0 + for i,v in ipairs(seq) do + sum = sum + i*v + end + assert(sum == 30) + end + do -- pairs + local sum = 0.0 + for i,v in pairs(seq) do + sum = sum + i*v + end + assert(sum == 30) + end + do -- next + local sum = 0.0 + for i,v in next,seq,-1 do + sum = sum + i*v + end + assert(sum == 30) + end + seq:destroy() +end + require 'allocators.general' do -- custom allocator local seq: sequence(integer, GeneralAllocator) = {1,2,3} diff --git a/tests/span_test.nelua b/tests/span_test.nelua index 734882e8..2d4d2c98 100644 --- a/tests/span_test.nelua +++ b/tests/span_test.nelua @@ -1,4 +1,5 @@ require 'span' +require 'iterators' do -- pointer to span local arr: array(integer, 4) = {1,2,3,4} @@ -24,6 +25,32 @@ do -- array to span assert(arr[0] == 5) end +do -- iterators + local arr: array(integer, 4) = {1,2,3,4} + local s: span(integer) = &arr + do -- ipairs + local sum = 0.0 + for i,v in ipairs(s) do + sum = sum + (i+1)*v + end + assert(sum == 30) + end + do -- pairs + local sum = 0.0 + for i,v in pairs(s) do + sum = sum + (i+1)*v + end + assert(sum == 30) + end + do -- next + local sum = 0.0 + for i,v in next,s,-1 do + sum = sum + (i+1)*v + end + assert(sum == 30) + end +end + require 'vector' do -- vector to span local vec: vector(integer) = {1,2,3,4} diff --git a/tests/vector_test.nelua b/tests/vector_test.nelua index 98574450..843d0162 100644 --- a/tests/vector_test.nelua +++ b/tests/vector_test.nelua @@ -109,6 +109,16 @@ do -- insert vec:destroy() end +do -- ipairs + local vec: vector(number) = {1,2,3,4} + local sum: number = 0.0 + for i,v in ipairs(vec) do + sum = sum + (i+1)*v + end + assert(sum == 30) + vec:destroy() +end + require 'allocators.general' do -- custom allocator local vec: vector(integer, GeneralAllocator) = {1,2,3}