Open amyjko opened 8 months ago
Hi Amy! Where should we get started?
Building this has a pretty long list of implementation tasks:
Tokenizer.ts
and Sym.ts
to define new token types for the parentheses, square brackets, and commas. Those are already used for other symbol types, so we'd need to define new symbol types and include them in Tokenizer.test.ts
to verify correct tokenizationTokenizer.ts
's list of symbols on the patterns that match for them.Range
that extends Node to represent a parsed rangeparseType.ts
to parse a Range
where a number type might be expectedparseExpression.ts
to parse a Range
Parser.test.ts
to check range parsing correctnessRangeType
that extends Type
and defining its acceptsAll
method to implement number range checking semantics described in the designRange
in a new RangeBasis.ts
file, like NumberBasis.ts
, including functions like ∋
described in the design spec.Match.ts
to account for rangesRangeValue
type that extends Value
, since those need to be checked when a Match
is being evaluatedRange
, RangeType
, and RangeValue
in en-US.json
, and placeholders in all other supported locales, giving examples of how to use them.I'm probably forgetting something.
There's a lot to learn about programming language implementation to make this work; but there are also lots of existing design patterns in the implementation that you could follow. So it's a big project, but possible!
We began the lengthy process of incorporating number ranges. As you can see this is a multi-step task and we were able to get the first three completed. There are commits made to the 398-number-ranges branch under my account. We did not pull request since we did not complete Number Ranges, but next steps would be to create the Range file that extends Node. Jessica and I have unassigned ourselves, thank you for everything!
We define new token types to represent range symbols in Sym.ts
: NumberExcludeOpen
, NumberExcludeClose
, NumberIncludeOpen
, and NumberIncludeClose
.
And we updated Tokenizer.ts
accordingly:
const ListOpenPattern = { pattern: LIST_OPEN_SYMBOL, types: [Sym.ListOpen, Sym.NumberIncludeOpen] };
const ListClosePattern = { pattern: LIST_CLOSE_SYMBOL, types: [Sym.ListClose, Sym.NumberIncludeClose] };
{ pattern: EVAL_OPEN_SYMBOL, types: [Sym.EvalOpen, Sym.NumberExcludeOpen] },
{ pattern: EVAL_CLOSE_SYMBOL, types: [Sym.EvalClose, Sym.NumberExcludeClose] },
Adding tests to Tokenizer.test.ts to verify correct tokenization We verified correct tokenization of ranges by adding tests to ensure the tokenizer correctly identifies range expressions. Tests included various range expressions, such as:
['(0, 1)', '(|0|,|1|)|'],
['(-1, 1)', '(|-1|,|1|)|'],
['[0, 1]', '[|0|,|1|]|'],
['[-1, 1]', '[|-1|,|1|]|'],
['(0.5, 1.5)', '(|0.5|,|1.5|)|'],
['[-1.5, 1.5]', '[|-1.5|,|1.5|]|'],
['(0,∞)', '(|0|,|∞|)|'],
['[0,∞]', '[|0|,|∞|]|'],
['(-∞,∞)', '(|-∞|,|∞|)|'],
['[-∞,∞]', '[|-∞|,|∞|]|'],
@NushaS @ericazqyy @jfm2003
@NushaS @ericazqyy Thank you for the extensive update! Where does your progress live? I don't see a reference to a branch anywhere in your comment or in the issue body. Please provide that, so others can build on your work.
Hey Amy! As I briefly mentioned above, the branch that we worked on was the 398-number-ranges branch. Here is the link to its page: https://github.com/wordplaydev/wordplay/tree/398-number-ranges . Please let us know if there are any issues with accessing it or if anything else is needed from us in order for others to continue working. Thank you!
What's the problem?
There are many places where ranges are helpful to have syntactically:
number ??? [1 ‥ 10] 'small' 'large'
)Because there is no concept of a range in the language, these are harder to express.
What's the design idea?
Add syntactic sugar for a range constraint and link it to various places in the language to make expression easier.
Design specification
Add range syntactic sugar for types and matches. We would do this by mirroring mathematical range syntax using parentheses and brackets to include (
[
,]
) or exclude boundaries ((
,)
), but declaring a unique symbol for a range:‥
, which borrows from the integer interval syntax in math notation.Here are some examples:
fingercount•[1,10]
fingercount
can be any real number between 1 and 10 inclusivenumber ?? (0,]: 'positive' 0: 'zero' 'negative'
number
maps to positive if greater than zero(-100,100) ∋ number
checks ifnumber
is greater than-100
and less than100
The grammar for a range would be:
We can disambiguate this from lists and evaluations by the comma after the first expression.
Ranges are typed as infinite sets of numbers. They can be used as a number type, in a match expression to match on a range, and they have functions like ∋ that check set containment, or conversions to lists or finite sets.
One limitation on type checking is that it would only work for number literals. Generic numbers would always fail to be in the range, and most computation would generally compute unbounded numbers, since they could be anything. We could generate range types on inequality statements when there are literal bounds, to preserve some type information.