def _build_table_record_item(value): item = None if value is None: item = nodes.Primitive() item.type = nodes.Primitive.T_NIL elif value is True: item = nodes.Primitive() item.type = nodes.Primitive.T_TRUE elif value is False: item = nodes.Primitive() item.type = nodes.Primitive.T_FALSE elif isinstance(value, int): item = nodes.Constant() item.value = value item.type = nodes.Constant.T_INTEGER elif isinstance(value, float): item = nodes.Constant() item.value = value item.type = nodes.Constant.T_FLOAT elif isinstance(value, str): item = nodes.Constant() item.value = value item.type = nodes.Constant.T_STRING return item
def _fill_massive_refs(info, simple, massive, iterators): ref = info.references[1] holder = _get_holder(ref.path) src = info.assignment.expressions.contents[0] assert isinstance(src, (nodes.FunctionCall, nodes.Vararg, nodes.Primitive)) if isinstance(holder, nodes.Assignment): dst = holder.destinations.contents[0] assert len(info.references) == 2 orig = info.references[0].identifier assignment = ref.path[-3] assert isinstance(assignment, nodes.Assignment) massive.append((orig, info.assignment, assignment, dst)) elif isinstance(holder, nodes.IteratorWarp): assert len(info.references) == 2 iterators.append((info.assignment, src, holder)) elif isinstance(src, nodes.Primitive) and src.type == src.T_NIL: assert len(info.references) == 2 # Create a new primitive, so it won't mess with the # writer's ignore list src = nodes.Primitive() src.type = nodes.Primitive.T_NIL simple.append((info, ref, src))
def _build_primitive(state, value): node = nodes.Primitive() if value is True or value == T_TRUE: node.type = nodes.Primitive.T_TRUE elif value is False or value == T_FALSE: node.type = nodes.Primitive.T_FALSE else: assert value is None or value == T_NIL node.type = nodes.Primitive.T_NIL return node
def insert_table_record(constructor, key, value): array = constructor.array.contents records = constructor.records.contents if isinstance(key, nodes.MULTRES): assert len(records) == 0 or\ isinstance(records[-1], nodes.TableRecord) records.append(value) return while isinstance(key, nodes.Constant) and\ key.type == key.T_INTEGER and\ key.value >= 0: index = key.value if index == 1 and len(array) == 0: record = nodes.ArrayRecord() record.value = nodes.Primitive() record.value.type = nodes.Primitive.T_NIL array.append(record) if (index > len(array)): break record = nodes.ArrayRecord() record.value = value if len(array) == 0 or index == len(array): array.append(record) else: array[index] = record return record = nodes.TableRecord() record.key = key record.value = value if len(records) == 0: records.append(record) return last = records[-1] if isinstance(last, (nodes.FunctionCall, nodes.Vararg)): records.insert(-1, record) else: records.append(record)
def _unwarp_expression(body, end, true, false): parts = [] if true is not None: terminator_index = min(true.index, false.index) if end is not None: terminator_index = min(end.index, terminator_index) else: assert end is not None terminator_index = end.index terminators = set((true, false, end)) subexpression_start = 0 i = 0 while i < len(body) - 1: block = body[i] warp = block.warp target = _get_target(warp) # # A chance for # (foo and (bar and y or z)) or x # type expressions, because the first "foo and ... )) or" part # will be broken by the "or z))" part in the code below. # # So we are going to intercept subexpressions by it's start # instead of an end, but only if we are already at the # subexpression start (so nothing formally changes, but creates # a bit more correct execution order) # if target.index < terminator_index: if i != subexpression_start: i += 1 continue target_index = body.index(target) last_block = body[target_index - 1] last_block_target = _get_target(last_block.warp) if last_block_target.index < terminator_index: i += 1 continue assert last_block_target in terminators subexpression = body[i:target_index] else: assert target in terminators while i < len(body) - 2: next_block = body[i + 1] next_target = _get_target(next_block.warp) if next_target != target: break next_inv = _is_inverted(next_block.warp, true, end) this_inv = _is_inverted(warp, true, end) # Special hack for unary expressions (x, not x)... if next_inv != this_inv: break block = next_block warp = next_block.warp i += 1 subexpression = body[subexpression_start:i + 1] last_block = subexpression[-1] last_block_index = body.index(last_block) next_block = body[last_block_index + 1] operator = _get_operator(last_block, true, end) subexpression = _compile_subexpression(subexpression, operator, last_block, next_block, true, end) parts.append(subexpression) parts.append(operator) i = last_block_index + 1 subexpression_start = i last = body[-1] if isinstance(last.warp, nodes.ConditionalWarp): if _is_inverted(last.warp, true, end): last = _invert(last.warp.condition) else: last = last.warp.condition parts.append(last) else: assert isinstance(last.warp, (nodes.EndWarp, nodes.UnconditionalWarp)) src = _get_last_assignment_source(last) if src is None: src = nodes.Primitive() if last.warp.target == true: src.type = nodes.Primitive.T_TRUE else: src.type = nodes.Primitive.T_FALSE parts.append(src) return parts
def _unwarp_loop(start, end, body): if len(body) > 0: last = body[-1] else: last = start if isinstance(start.warp, nodes.IteratorWarp): assert isinstance(last.warp, nodes.UnconditionalWarp) assert last.warp.target == start loop = nodes.IteratorFor() loop.statements.contents = body loop.identifiers = start.warp.variables loop.expressions = start.warp.controls loop._addr = body[0].first_address _set_flow_to(start, body[0]) elif isinstance(start.warp, nodes.NumericLoopWarp): assert isinstance(last.warp, nodes.UnconditionalWarp) assert last.warp.target == start loop = nodes.NumericFor() loop.statements.contents = body loop.variable = start.warp.index loop.expressions = start.warp.controls loop._addr = body[0].first_address _set_flow_to(start, body[0]) # While (including "while true" and "repeat until false" which will be # while true) elif isinstance(last.warp, nodes.UnconditionalWarp): assert last.warp.target == start # while true if _is_flow(start.warp): loop = nodes.While() loop.expression = nodes.Primitive() loop.expression.type = nodes.Primitive.T_TRUE loop.statements.contents = body else: # There shouldn't be many problems similar to ifs, as # we are processing loops in the order from innermost # to outermost for i, block in enumerate(body): assert len(block.contents) == 0 if _is_flow(block.warp): break assert i < len(body) expression = [start] + body[:i] body = body[i:] # Sometimes expression may decide to jump to the # outer loop start instead _fix_expression(expression, start, end) true = body[0] false = end expression = _compile_expression(expression, None, true, false) # If something jumps to the start (instead of the end) # - that's a nested if loop = nodes.While() loop.expression = expression loop.statements.contents = body _fix_nested_ifs(body, start) _set_flow_to(start, body[0]) # Repeat until else: assert isinstance(last.warp, nodes.ConditionalWarp) assert last.warp.false_target == start i = len(body) - 1 while i >= 0: block = body[i] warp = block.warp if _is_flow(warp): i += 1 break if len(block.contents) != 0: break i -= 1 expression = body[i:] body = body[:i + 1] assert len(expression) > 0 first = expression[0] if _is_jump(first.warp): # Don't append to the body - it already has it expression.pop(0) body[-1].contents.append(nodes.Break()) false = body[0] # Don't use end as it could be broken by a previous # repeat until pass true = expression[-1].warp.true_target loop = nodes.RepeatUntil() loop.expression = _compile_expression(expression, None, true, false) start_copy = copy.copy(start) start.contents = [] if len(body) > 1: _set_flow_to(start_copy, body[1]) else: _set_end(start_copy) _set_flow_to(start, start_copy) body[0] = start_copy loop.statements.contents = body return loop
def insert_table_record(constructor, key, value, replace, allow_duplicates=True): array = constructor.array.contents records = constructor.records.contents if isinstance(key, nodes.MULTRES): assert len(records) == 0 \ or isinstance(records[-1], nodes.TableRecord) records.append(value) return True while isinstance(key, nodes.Constant) \ and key.type == key.T_INTEGER \ and key.value >= 0: index = key.value if index == 1 and len(array) == 0: record = nodes.ArrayRecord() record.value = nodes.Primitive() record.value.type = nodes.Primitive.T_NIL array.append(record) if index > len(array): break record = nodes.ArrayRecord() record.value = value if len(array) == 0 or index == len(array): array.append(record) return True elif replace: array[index] = record return True else: current_value = array[index].value if isinstance(current_value, nodes.Primitive ) and current_value.type == nodes.Primitive.T_NIL: array[index] = record return True return False # Check for record duplicates # This isn't nearly as important as duplicate protection with arrays, since both values # end up in the table to the user can make sense of what happened. Nonetheless, we should still # reject stuff like this. if not allow_duplicates: for rec in records: if isinstance(rec, nodes.TableRecord): if is_equal(rec.key, key, strict=False): return False record = nodes.TableRecord() record.key = key record.value = value if len(records) == 0: records.append(record) return True last = records[-1] if isinstance(last, (nodes.FunctionCall, nodes.Vararg)): records.insert(-1, record) else: records.append(record) return True