How make setParseAction work when chain several definitions (like FLOAT derive from INT) building AST - parsing

I'm struggling to make work setParseAction when inherit definitions (I don't know how express this in english, so the example):
from __future__ import division
from decimal import Decimal
from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \
, Combine, Optional, nums, Or, Forward, ZeroOrMore, StringEnd, alphanums, Suppress \
, sglQuotedString, dblQuotedString, Group \
, restOfLine, Regex, stringEnd
class ASTNode(object):
def __init__(self, tokens):
self.tokens = tokens
self.assignFields()
def __str__(self):
return self.__class__.__name__ + ':' + str(self.__dict__)
__repr__ = __str__
class ConstantNode(ASTNode):
def assignFields(self):
#print " ", self.tokens
self.setValue(self.tokens[0])
def transform(self, value):
return value
def setValue(self, value):
self.constant = self.transform(value)
del self.tokens
class StringNode(ConstantNode):
pass
class BoolNode(ConstantNode):
def transform(self, value):
return bool(value)
class IntNode(ConstantNode):
def transform(self, value):
return int(value)
class FloatNode(ConstantNode):
def transform(self, value):
print value
return Decimal(value)
class AssignmentNode(ASTNode):
def assignFields(self):
#print self.tokens
self.lhs, self.rhs = self.tokens
del self.tokens
LPAR, RPAR, LBRACK, RBRACK, LBRACE, RBRACE, SEMI, COMMA = map(Suppress, "()[]{};,")
PLUS = Literal("+")
MINUS = Literal("-")
MULT = Literal("*")
DIV = Literal("/")
ASSIGN = Literal("=")
POINT = Literal('.')
TRUE = Literal('True')
FALSE = Literal('False')
SEP = Literal(':').suppress()
NAME = Word(alphas + '_?', alphanums + '_?')
TYPE = SEP + NAME
COMMENT = "#" + restOfLine
BOOLEANS = TRUE | FALSE
BOOLEANS.setParseAction(BoolNode)
EXPR = Forward()
ADDOP = PLUS | MINUS
MULTOP = MULT | DIV
PLUSORMINUS = PLUS | MINUS
#Strings
STR = dblQuotedString.setParseAction(ConstantNode) | sglQuotedString.setParseAction(ConstantNode)
STRINGS = STR
#Numbers
NUMBER = Word(nums)
INTEGER = Combine(Optional(PLUSORMINUS) + NUMBER)
FLOATNUMBER = Combine(INTEGER.copy() +
Optional(POINT + Optional(NUMBER)) +
Optional(INTEGER.copy())
)
MONEY = Combine(FLOATNUMBER.copy() + Word("$").suppress())
TYPED_FLOATNUMBER = Combine(FLOATNUMBER + Word(alphas))
INTEGER.setParseAction(IntNode)
FLOATNUMBER.setParseAction(FloatNode)
NUMBERS = MONEY | TYPED_FLOATNUMBER | FLOATNUMBER
TEST_GRAMMAR = """
#Single values
True
False
1 #Int32
1.0 #Float
1$ #MONEY
25.3mt #Typed number"""
Everything parse, but the Boolean and Int node are not called, only the float.
['True']
['False']
1
[FloatNode:{'constant': Decimal('1')}]
1.0
[FloatNode:{'constant': Decimal('1.0')}]
['1']
['25.3mt']
[ConstantNode:{'constant': "'hello world'"}]
[ConstantNode:{'constant': '"hello world"'}]
['2002-08-10']
['100000']
['2002-08-10-100000']
1
[AssignmentNode:{'rhs': FloatNode:{'constant': Decimal('1')}, 'lhs': 'x'}]
1.0
[AssignmentNode:{'rhs': FloatNode:{'constant': Decimal('1.0')}, 'lhs': 'x'}]
[AssignmentNode:{'rhs': '1', 'lhs': 'x'}]
[AssignmentNode:{'rhs': '12.2mt', 'lhs': 'x'}]
I understand that setParseAction is tied to the definition of a partial grammar. However, I find it don't "clear" if chain something like FLOATNUMBER because is based on INTEGER.

You left out the code that does the actual parsing, so I added this code:
for line in TEST_GRAMMAR.splitlines():
if not line or line[0] == '#': continue
print (BOOLEANS^INTEGER^NUMBERS).parseString(line)
Giving this output:
[BoolNode:{'constant': True}]
[BoolNode:{'constant': False}]
[IntNode:{'constant': 1}]
1.0
[FloatNode:{'constant': Decimal('1.0')}]
['1']
['25.3mt']
I also had to fix a minor bug in BoolNode:
class BoolNode(ConstantNode):
def transform(self, value):
return value.lower()=='true' #bool(value)
In transform, value is going to be one of the strings "True" or "False", but the bool value of both of these strings is True - only the empty string "" will return a bool of False.
One of the problems you have is that your definition of FLOAT will also match an INTEGER, so you might consider redefining FLOAT to require a leading, trailing, or embedded decimal point. I got around this by using '^' instead of '|' as the "or" operator. '^' will test all the given alternatives and select the longest match, '|' will short-circuit and select the first match.

Related

Ruby mathematical formula from string with 'x'

In order not to get rusty I want to refresh my knowledge of pure ruby by solving some algorithms. I can't solve a larger algorithm without solving a smaller one like the example below.
Have the function missing_digit(str) take the str parameter, which will be a simple mathematical formula with three numbers, a single operator (+, -, *, or /) and an equal sign (=) and return the digit that completes the equation. In one of the numbers in the equation, there will be an x character, and your program should determine what digit is missing. For example, if str is "3x + 12 = 46" then your program should output 4.
Examples
Input: "4 - 2 = x"
Output: 2
Input: "1x0 * 12 = 1200"
Output: 0
I think I found the solution for python but I can't find the corresponding Ruby code anywhere.
Python and Ruby are quite similar, though trying to convert this without some basic TDD would have been difficult. Here is the converted to Ruby file from your python example. I would refactor this code but the simple tests here pass, those given in your linked example.
string_math_x.rb
class StringMathX
def self.calculate(str)
exp = str.split()
first_operand = exp[0]
operator = exp[1]
second_operand = exp[2]
resultant = exp[-1]
# If x is present in resultant
if resultant[/x/]
first_operand = first_operand.to_i
second_operand = second_operand.to_i
if operator == '+'
res = first_operand + second_operand
elsif operator == '-'
res = first_operand - second_operand
elsif operator == '*'
res = first_operand * second_operand
else
res = first_operand / second_operand
end
return res
end
# If x in present in operands
# If x in the first operand
if first_operand == 'x'
x = first_operand.to_i
second_operand = second_operand.to_i
if operator == '+'
res = resultant - second_operand
elsif operator == '-'
res = resultant + second_operand
elsif operator == '*'
res = resultant / second_operand
else
res = resultant / second_operand
end
# If x is in the second operand
else
x = second_operand.to_i
first_operand = first_operand.to_i
if operator == '+'
res = resultant-first_operand
elsif operator == '-'
res = first_operand - second_operand
elsif operator == '*'
res = resultant.to_i / first_operand.to_i
else
res = first_operand.to_i / resultant.to_i
end
end
res = res.to_s
k = 0
for i in [*0..x]
if i == x
result = res[k]
break
else
k += 1
end
end
result.to_i
end
end
./test/test.rb
require 'minitest/autorun'
require_relative '../lib/string_math_x'
class StringMathXTest < Minitest::Test
def test_basic_subtration
input = '4 - 2 = x'
assert(StringMathX.calculate(input) == 2, 'outputs 2')
end
def test_whats_up_returns_doc
input = '1x0 * 12 = 1200'
assert(StringMathX.calculate(input) == 0, 'outputs 0')
end
end
To run this you may need to gem install minitest
Then run ruby test/test.rb
def findx(str)
s = str.sub('=', '==')
i = s.index('x')
pre = s[0,i]
post = s[i+1..-1]
('0'..'9').find { |d| eval(pre+d+post) rescue nil }&.to_i
end
findx("4 - 2 = x") #=> 2
findx("1x0 * 12 = 1200") #=> 0
findx("3**x = 81") #=> 4
findx("1/x == 2.0").nil? #=> true
rescue nil is needed in case division by zero is performed. & is the safe harbor operator. It returns nil, disregarding all that follows, if the part before it returns nil.

Making a print function repeat on a new line everytime it prints

So I want this final print function to print its function on a new line every time it prints. I've tried various "\n" placements to make it work but to no avail. Any tips?
from datetime import date
currentYear = date.today().year
print('Hi. What is your name?')
name = input()
while True:
try:
print('How old are you, ' + name + '?')
age = int(input())
if age >= 0:
break
else:
print('That is not a valid number.')
except ValueError:
print('That is not a valid number')
ageinHundred = 100 - int(age)
y = currentYear + int(ageinHundred)
t = 'You will be 100 years old in the year ' + str(int((y)))
print(t)
print('Give me another number')
num = input()
f = (int(num) * t)
print(f)
I want the final print function (print(f)) to print f multiple times on a new line each time. Not one after the other like the above code does now.
Thanks!
Change the last couple of lines to:
# Put t inside a list so it does list multiplication instead
# of string multiplication
f = int(num) * [t]
# Then join the individual f-lists with newlines and print
print("\n".join(f))
For the f = line, inspect f to get a better idea of what's going on there.
For the join part, join takes a list of strings, inserts the given string (in this case "\n"; a newline), and "joins" it all together. Get used to using join. It is a very helpful function.
Try this:
from datetime import date
currentYear = date.today().year
print('Hi. What is your name?')
name = input()
while True:
try:
print('How old are you, ' + name + '?')
age = int(input())
if age >= 0:
break
else:
print('That is not a valid number.')
except ValueError:
print('That is not a valid number')
ageinHundred = 100 - int(age)
y = currentYear + int(ageinHundred)
t = 'You will be 100 years old in the year ' + str(int((y)))
print(t)
print('Give me another number')
num = input()
for i in range(0,int(num)):
print(t)

Extracting information from ParseResults in pyparsing

I'm discovering the pyparsing module which is really cool. I'm trying to parse a set of simple boolean expressions in which some identifiers (foo/bar/bla and zoo) are compared to numeric values. The parser is used to check that user expression is correct but I would like also to get the name of the identifiers used in the expression (i.e which combination of foo/bar/bla and zoo was used). I can't get a simple way to do it.
In the example below foo and bar are used in the expression. But how can I get this information ?
Best
from pyparsing import oneOf
from pyparsing import Group
from pyparsing import Regex
from pyparsing import operatorPrecedence
from pyparsing import opAssoc
from pyparsing import Literal
from pyparsing import Word
from pyparsing import nums
from pyparsing import Combine
from pyparsing import Optional
from pyparsing import CaselessLiteral
from pyparsing import alphanums
from pyparsing import quotedString
from pyparsing import Forward
lparen = Literal("(")
rparen = Literal(")")
and_operator = CaselessLiteral("and")
or_operator = CaselessLiteral("or")
comparison_operator = oneOf(['==','!=','>','>=','<', '<='])
point = Literal('.')
e = CaselessLiteral('E')
plusorminus = Literal('+') | Literal('-')
number = Word(nums)
integer = Combine( Optional(plusorminus) + number )
float_nb = Combine( integer +
Optional( point + Optional(number) ) +
Optional( e + integer ))
value = float_nb
value.resultsName = 'value'
identifier = oneOf(['foo','bar', 'bla', 'zoo'], caseless=False)
identifier.resultsName = 'key'
group_1 = Group(identifier + comparison_operator + value)
group_2 = Group(value + comparison_operator + identifier)
comparison = group_1 | group_2
boolean_expr = operatorPrecedence(
comparison,
[(and_operator, 2, opAssoc.LEFT),
(or_operator, 2, opAssoc.LEFT)])
boolean_expr_par = "(" + boolean_expr + ")"
expression = Forward()
expression << boolean_expr | boolean_expr_par
exp = expression.parseString('2.5 > foo and (3 < bar or (foo > 10 and bar < 3)) ' , parseAll=True)
# Now how can I get the 'identifiers used in exp' ?
I had a similar problem.
I used the 'setParseAction' method in your 'identifier' parser to set a function recording each occurrence of the token matching 'identifier'. Then I print the recorded items:
I declare :
idSet = set()
def recordID(tokens):
idSet.add(tokens[0])
return
I modify your 'identifier' parser as follows:
identifier = oneOf(['foo','bar', 'bla', 'zoo'], caseless=False).setParseAction(recordID)
At the end of you script I print 'idSet':
exp = expression.parseString('2.5 > foo and (3 < bar or (foo > 10 and bar < 3)) ' , parseAll=True)
print(idSet)
It gives the following outcome:
{'foo', 'bar'}

Parsing a TeX-like language with lpeg

I am struggling to get my head around LPEG. I have managed to produce one grammar which does what I want, but I have been beating my head against this one and not getting far. The idea is to parse a document which is a simplified form of TeX. I want to split a document into:
Environments, which are \begin{cmd} and \end{cmd} pairs.
Commands which can either take an argument like so: \foo{bar} or can be bare: \foo.
Both environments and commands can have parameters like so: \command[color=green,background=blue]{content}.
Other stuff.
I also would like to keep track of line number information for error handling purposes. Here's what I have so far:
lpeg = require("lpeg")
lpeg.locale(lpeg)
-- Assume a lot of "X = lpeg.X" here.
-- Line number handling from http://lua-users.org/lists/lua-l/2011-05/msg00607.html
-- with additional print statements to check they are working.
local newline = P"\r"^-1 * "\n" / function (a) print("New"); end
local incrementline = Cg( Cb"linenum" )/ function ( a ) print("NL"); return a + 1 end , "linenum"
local setup = Cg ( Cc ( 1) , "linenum" )
nl = newline * incrementline
space = nl + lpeg.space
-- Taken from "Name-value lists" in http://www.inf.puc-rio.br/~roberto/lpeg/
local identifier = (R("AZ") + R("az") + P("_") + R("09"))^1
local sep = lpeg.S(",;") * space^0
local value = (1-lpeg.S(",;]"))^1
local pair = lpeg.Cg(C(identifier) * space ^0 * "=" * space ^0 * C(value)) * sep^-1
local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
local parameters = (P("[") * list * P("]")) ^-1
-- And the rest is mine
anything = C( (space^1 + (1-lpeg.S("\\{}")) )^1) * Cb("linenum") / function (a,b) return { text = a, line = b } end
begin_environment = P("\\begin") * Ct(parameters) * P("{") * Cg(identifier, "environment") * Cb("environment") * P("}") / function (a,b) return { params = a[1], environment = b } end
end_environment = P("\\end{") * Cg(identifier) * P("}")
texlike = lpeg.P{
"document";
document = setup * V("stuff") * -1,
stuff = Cg(V"environment" + anything + V"bracketed_stuff" + V"command_with" + V"command_without")^0,
bracketed_stuff = P"{" * V"stuff" * P"}" / function (a) return a end,
command_with =((P("\\") * Cg(identifier) * Ct(parameters) * Ct(V"bracketed_stuff"))-P("\\end{")) / function (i,p,n) return { command = i, parameters = p, nodes = n } end,
command_without = (( P("\\") * Cg(identifier) * Ct(parameters) )-P("\\end{")) / function (i,p) return { command = i, parameters = p } end,
environment = Cg(begin_environment * Ct(V("stuff")) * end_environment) / function (b,stuff, e) return { b = b, stuff = stuff, e = e} end
}
It almost works!
> texlike:match("\\foo[one=two]thing\\bar")
{
command = "foo",
parameters = {
{
one = "two",
},
},
}
{
line = 1,
text = "thing",
}
{
command = "bar",
parameters = {
},
}
But! First, I can't get the line number handling part to work at all. The function within incrementline is never fired.
I also can't quite work out how nested capture information is passed to handling functions (which is why I have scattered Cg, C and Ct semirandomly over the grammar). This means that only one item is returned from within a command_with:
> texlike:match("\\foo{text \\command moretext}")
{
command = "foo",
nodes = {
{
line = 1,
text = "text ",
},
},
parameters = {
},
}
I would also love to be able to check that the environment start and ends match up but when I tried to do so, my back references from "begin" were not in scope by the time I got to "end". I don't know where to go from here.
Late answer but hopefully it'll offer some insight if you're still looking for a solution or wondering what the problem was.
There are a couple of issues with your grammar, some of which can be tricky to spot.
Your line increment here looks incorrect:
local incrementline = Cg( Cb"linenum" ) /
function ( a ) print("NL"); return a + 1 end,
"linenum"
It looks like you meant to create a named capture group and not an anonymous group. The backcapture linenum is essentially being used like a variable. The problem is because this is inside an anonymous capture, linenum will not update properly -- function(a) will always receive 1 when called. You need to move the closing ) to the end so "linenum" is included:
local incrementline = Cg( Cb"linenum" /
function ( a ) print("NL"); return a + 1 end,
"linenum")
Relevant LPeg documentation for Cg capture.
The second problem is with your anything non-terminal rule:
anything = C( (space^1 + (1-lpeg.S("\\{}")) )^1) * Cb("linenum") ...
There are several things to be careful here. First, a named Cg capture (from incrementline rule once it's fixed) doesn't produce anything unless it's in a table or you backref it. The second major thing is that it has an adhoc scope like a variable. More precisely, its scope ends once you close it in an outer capture -- like what you're doing here:
C( (space^1 + (...) )^1)
Which means by the time you reference its backcapture with * Cb("linenum"), that's already too late -- the linenum you really want already closed its scope.
I always found LPeg's re syntax a bit easier to grok so I've rewritten the grammar with that instead:
local grammar_cb =
{
fold = pairfold,
resetlinenum = resetlinenum,
incrementlinenum = incrementlinenum, getlinenum = getlinenum,
error = error
}
local texlike_grammar = re.compile(
[[
document <- '' -> resetlinenum {| docpiece* |} !.
docpiece <- {| envcmd |} / {| cmd |} / multiline
beginslash <- cmdslash 'begin'
endslash <- cmdslash 'end'
envcmd <- beginslash paramblock? {:beginenv: envblock :} (!endslash docpiece)*
endslash openbrace {:endenv: =beginenv :} closebrace / &beginslash {} -> error .
envblock <- openbrace key closebrace
cmd <- cmdslash {:command: identifier :} (paramblock? cmdblock)?
cmdblock <- openbrace {:nodes: {| docpiece* |} :} closebrace
paramblock <- opensq ( {:parameters: {| parampairs |} -> fold :} / whitesp) closesq
parampairs <- parampair (sep parampair)*
parampair <- key assign value
key <- whitesp { identifier }
value <- whitesp { [^],;%s]+ }
multiline <- (nl? text)+
text <- {| {:text: (!cmd !closebrace !%nl [_%w%p%s])+ :} {:line: '' -> getlinenum :} |}
identifier <- [_%w]+
cmdslash <- whitesp '\'
assign <- whitesp '='
sep <- whitesp ','
openbrace <- whitesp '{'
closebrace <- whitesp '}'
opensq <- whitesp '['
closesq <- whitesp ']'
nl <- {%nl+} -> incrementlinenum
whitesp <- (nl / %s)*
]], grammar_cb)
The callback functions are straight-forwardly defined as:
local function pairfold(...)
local t, kv = {}, ...
if #kv % 2 == 1 then return ... end
for i = #kv, 2, -2 do
t[ kv[i - 1] ] = kv[i]
end
return t
end
local incrementlinenum, getlinenum, resetlinenum do
local line = 1
function incrementlinenum(nl)
assert(not nl:match "%S")
line = line + #nl
end
function getlinenum() return line end
function resetlinenum() line = 1 end
end
Testing the grammar with a non-trivial tex-like str with multiple lines:
local test1 = [[\foo{text \bar[color = red, background = black]{
moretext \baz{
even
more text} }
this time skipping multiple
lines even, such wow!}]]
Produces the follow AST in lua-table format:
{
command = "foo",
nodes = {
{
text = "text",
line = 1
},
{
parameters = {
color = "red",
background = "black"
},
command = "bar",
nodes = {
{
text = " moretext",
line = 2
},
{
command = "baz",
nodes = {
{
text = "even ",
line = 3
},
{
text = "more text",
line = 4
}
}
}
}
},
{
text = "this time skipping multiple",
line = 7
},
{
text = "lines even, such wow!",
line = 9
}
}
}
And a second test for begin/end environments:
local test2 = [[\begin[p1
=apple,
p2=blue]{scope} scope foobar
\end{scope} global foobar]]
Which seems to give approximately what you're looking for:
{
{
{
text = " scope foobar",
line = 3
},
parameters = {
p1 = "apple",
p2 = "blue"
},
beginenv = "scope",
endenv = "scope"
},
{
text = " global foobar",
line = 4
}
}

How to make LPeg.match return nil

I'm currently getting familiar with the LPeg parser module. For this I want to match a version string (e.g. 11.4) against a list.
Such a list is a string with a tight syntax that can also contain ranges. Here is an EBNF-like, but in any case quite simple grammar (I write it down because LPeg code below can be a bit difficult to read):
S = R, { ',', R }
R = N, [ '-', N ]
N = digit+, [ '.', digit+ ]
An example string would be 1-9,10.1-11,12. Here is my enormous code:
local L = require "lpeg"
local LV, LP, LC, LR, floor = L.V, L.P, L.C, L.R, math.floor
local version = "7.25"
local function check(a, op, b)
if op and a+0 <= version and version <= b+0 then
return a..op..b -- range
elseif not op and floor(version) == floor(a+0) then
return a -- single item
end
end
local grammar = LP({ "S",
S = LV"R" * (LP"," * LV"R")^0,
R = LV"V" * (LC(LP"-") * LV"V")^-1 / check,
V = LC(LV"D" * (LP"." * LV"D")^-1),
D = (LR("09")^1),
})
function checkversion(str)
return grammar:match(str)
end
So you would call it like checkversion("1-7,8.1,8.3,9") and if the current version is not matched by the list you should get nil.
Now, the trouble is, if all calls to check return nothing (meaning, if the versions do not match), grammar:match(...) will actually have no captures and so return the current position of the string. But this is exactly what I do not want, I want checkversion to return nil or false if there is no match and something that evaluates to true otherwise, actually just like string:match would do.
If I on the other hand return false or nil from check in case of a non-match, I end up with return values from match like nil, "1", nil, nil which is basically impossible to handle.
Any ideas?
I think you can or + it with a constant capture of nil:
grammar = grammar + lpeg.Cc(nil)
This is the pattern I eventually used:
nil_capturing_pattern * lpeg.Cc(nil)
I incorporated it into the grammar in the S rule (Note that this also includes changed grammar to "correctly" determine version order, since in version numbering "4.7" < "4.11" is true, but not in calculus)
local Minor_mag = log10(Minor);
local function check(a, am, op, b, bm)
if op then
local mag = floor(max(log10(am), log10(bm), Minor_mag, 1))+1;
local a, b, v = a*10^mag+am, b*10^mag+bm, Major*10^mag+Minor;
if a <= v and v <= b then
return a..op..b;
end
elseif a == Major and (am == "0" or am == Minor) then
return a.."."..am;
end
end
local R, V, C, Cc = lpeg.R, lpeg.V, lpeg.C, lpeg.Cc
local g = lpeg.P({ "S",
S = V("R") * ("," * V("R"))^0 * Cc(nil),
R = (V("Vm") + V("VM")) * (C("-") * (V("Vm") + V("VM")))^-1 / check,
VM = V("D") * Cc("0"),
Vm = V("D") * "." * V("D"),
D = C(R("09")^1),
});
Multiple returns from match are not impossible to handle, if you catch them in a way that makes handling them easier. I added a function matched that does that, and added the fallback return of false to your check.
do
local L = require "lpeg"
local LV, LP, LC, LR, floor = L.V, L.P, L.C, L.R, math.floor
local version = 6.25
local function check(a, op, b)
if op and a+0 <= version and version <= b+0 then
return a..op..b -- range
elseif not op and floor(version) == floor(a+0) then
return a -- single item
end
return false
end
local grammar = LP({ "S",
S = LV"R" * (LP"," * LV"R")^0,
R = LV"V" * (LC(LP"-") * LV"V")^-1 / check,
V = LC(LV"D" * (LP"." * LV"D")^-1),
D = (LR("09")^1),
})
local function matched(...)
local n = select('#',...)
if n == 0 then return false end
for i=1,n do
if select(i,...) then return true end
end
return false
end
function checkversion(ver,str)
version = ver
return matched(grammar:match(str))
end
end
I enclosed the whole thing in do ... end so that the local version which is used here as an upvalue to check would have constrained scope, and added a parameter to checversion() to make it clearer to run through few test cases. For example:
cases = { 1, 6.25, 7.25, 8, 8.5, 10 }
for _,v in ipairs(cases) do
print(v, checkversion(v, "1-7,8.1,8.3,9"))
end
When run, I get:
C:\Users\Ross\Documents\tmp\SOQuestions>q18793493.lua
1 true
6.25 true
7.25 false
8 true
8.5 true
10 false
C:\Users\Ross\Documents\tmp\SOQuestions>
Note that either nil or false would work equally well in this case. It just feels saner to have collected a list that can be handled as a normal Lua array-like table without concern for the holes.

Resources