chharvey / counterpoint

A robust programming language.
GNU Affero General Public License v3.0
2 stars 0 forks source link

Tokenize & Cook: Imaginary and Rational Literals #20

Open chharvey opened 4 years ago

chharvey commented 4 years ago

Tokenize the literal syntaxes for imaginary and rational numbers.

NonInteger ::=
    FloatTruncated |
    Float          |
    Imaginary      |
    Rational

FloatTruncated ::= SignedDigitSequenceDec "."
Float          ::= SignedDigitSequenceDec "." FractionalPart ExponentPart?

Imaginary ::= (Integer | Float) "i"

Rational ::= Integer "~" IntegerPositive

IntegerPositive ::=
    "\b"  (ZeroSequence "_"?)? [1-1]    ("_"? DigitSequenceBin)? |
    "\q"  (ZeroSequence "_"?)? [1-3]    ("_"? DigitSequenceQua)? |
    "\o"  (ZeroSequence "_"?)? [1-7]    ("_"? DigitSequenceOct)? |
    "\d"? (ZeroSequence "_"?)? [1-9]    ("_"? DigitSequenceDec)? |
    "\x"  (ZeroSequence "_"?)? [1-9a-f] ("_"? DigitSequenceHex)? |
    "\z"  (ZeroSequence "_"?)? [1-9a-z] ("_"? DigitSequenceHex)?

ZeroSequence ::= (ZeroSequence "_"?)? "0"

Update Mathematical Value (MV) for imaginary numbers.

MV(NonInteger ::= FloatTruncated)
    := MV(FloatTruncated)
MV(NonInteger ::= Imaginary)
    := MV(Imaginary)

MV(FloatTruncated ::= SignedDigitSequenceDec ".")
    := MV(SignedDigitSequenceDec)

MV(Imaginary ::= Integer "i")
    := MV(Integer)
MV(Imaginary ::= Float "i")
    := MV(Float)

Introduce new formula: Rational Value (RV). The Rational Value (RV) of a rational literal is an ordered pair consisting of the integers in lowest terms with respect to each other. Below, GreatestCommonDivisor refers to the Greatest Common Divisor algorithm.

RV(NonInteger ::= Rational)
    := RV(Rational)

RV(Rational ::= Integer "~" IntegerPositive)
    := MV(Integer) / GreatestCommonDivisor(MV(Integer), MV(IntegerPositive)) followed by
    MV(IntegerPositive) / GreatestCommonDivisor(MV(Integer), MV(IntegerPositive))

MV(IntegerPositive ::= "\b"  (ZeroSequence "_"?)? [1-1])
    := MV([1-1])
MV(IntegerPositive ::= "\q"  (ZeroSequence "_"?)? [1-3])
    := MV([1-3])
MV(IntegerPositive ::= "\o"  (ZeroSequence "_"?)? [1-7])
    := MV([1-7])
MV(IntegerPositive ::= "\d"? (ZeroSequence "_"?)? [1-9])
    := MV([1-9])
MV(IntegerPositive ::= "\x"  (ZeroSequence "_"?)? [1-9a-f])
    := MV([1-9a-f])
MV(IntegerPositive ::= "\z"  (ZeroSequence "_"?)? [1-9a-z])
    := MV([1-9a-z])

MV(IntegerPositive ::= "\b"  (ZeroSequence "_"?)? [1-1]    "_"? DigitSequenceBin)
    := MV([1-1])    *  2 ^ CodePointCount(DigitSequenceBin) + MV(DigitSequenceBin)
MV(IntegerPositive ::= "\q"  (ZeroSequence "_"?)? [1-3]    "_"? DigitSequenceQua)
    := MV([1-3])    *  4 ^ CodePointCount(DigitSequenceQua) + MV(DigitSequenceQua)
MV(IntegerPositive ::= "\o"  (ZeroSequence "_"?)? [1-7]    "_"? DigitSequenceOct)
    := MV([1-7])    *  8 ^ CodePointCount(DigitSequenceOct) + MV(DigitSequenceOct)
MV(IntegerPositive ::= "\d"? (ZeroSequence "_"?)? [1-9]    "_"? DigitSequenceDec)
    := MV([1-9])    * 10 ^ CodePointCount(DigitSequenceDec) + MV(DigitSequenceDec)
MV(IntegerPositive ::= "\x"  (ZeroSequence "_"?)? [1-9a-f] "_"? DigitSequenceHex)
    := MV([1-9a-f]) * 16 ^ CodePointCount(DigitSequenceHex) + MV(DigitSequenceHex)
MV(IntegerPositive ::= "\z"  (ZeroSequence "_"?)? [1-9a-z] "_"? DigitSequenceHTD)
    := MV([1-9a-z]) * 36 ^ CodePointCount(DigitSequenceHTD) + MV(DigitSequenceHTD)

CodePointCount(DigitSequenceBin)
    := the number of code points in DigitSequenceBin, excluding all "_"
CodePointCount(DigitSequenceQua)
    := the number of code points in DigitSequenceQua, excluding all "_"
CodePointCount(DigitSequenceOct)
    := the number of code points in DigitSequenceOct, excluding all "_"
CodePointCount(DigitSequenceDec)
    := the number of code points in DigitSequenceDec, excluding all "_"
CodePointCount(DigitSequenceHex)
    := the number of code points in DigitSequenceHex, excluding all "_"
CodePointCount(DigitSequenceHTD)
    := the number of code points in DigitSequenceHTD, excluding all "_"

MV([0-9a-z] ::= "0")  :=                            MV([0-9a-f] ::= "0")  :=                            MV([0-9] ::= "0")  :=                         MV([0-7] ::= "0")  :=                         MV([0-3] ::= "0")  :=                         MV([0-1] ::= "0")  :=                         0
MV([0-9a-z] ::= "1")  :=  MV([1-9a-z] ::= "1")  :=  MV([0-9a-f] ::= "1")  :=  MV([1-9a-f] ::= "1")  :=  MV([0-9] ::= "1")  :=  MV([1-9] ::= "1")  :=  MV([0-7] ::= "1")  :=  MV([1-7] ::= "1")  :=  MV([0-3] ::= "1")  :=  MV([1-3] ::= "1")  :=  MV([0-1] ::= "1")  :=  MV([1-1] ::= "1")  :=  1
MV([0-9a-z] ::= "2")  :=  MV([1-9a-z] ::= "2")  :=  MV([0-9a-f] ::= "2")  :=  MV([1-9a-f] ::= "2")  :=  MV([0-9] ::= "2")  :=  MV([1-9] ::= "2")  :=  MV([0-7] ::= "2")  :=  MV([1-7] ::= "2")  :=  MV([0-3] ::= "2")  :=  MV([1-3] ::= "2")  :=  2
MV([0-9a-z] ::= "3")  :=  MV([1-9a-z] ::= "3")  :=  MV([0-9a-f] ::= "3")  :=  MV([1-9a-f] ::= "3")  :=  MV([0-9] ::= "3")  :=  MV([1-9] ::= "3")  :=  MV([0-7] ::= "3")  :=  MV([1-7] ::= "3")  :=  MV([0-3] ::= "3")  :=  MV([1-3] ::= "3")  :=  3
MV([0-9a-z] ::= "4")  :=  MV([1-9a-z] ::= "4")  :=  MV([0-9a-f] ::= "4")  :=  MV([1-9a-f] ::= "4")  :=  MV([0-9] ::= "4")  :=  MV([1-9] ::= "4")  :=  MV([0-7] ::= "4")  :=  MV([1-7] ::= "4")  :=  4
MV([0-9a-z] ::= "5")  :=  MV([1-9a-z] ::= "5")  :=  MV([0-9a-f] ::= "5")  :=  MV([1-9a-f] ::= "5")  :=  MV([0-9] ::= "5")  :=  MV([1-9] ::= "5")  :=  MV([0-7] ::= "5")  :=  MV([1-7] ::= "5")  :=  5
MV([0-9a-z] ::= "6")  :=  MV([1-9a-z] ::= "6")  :=  MV([0-9a-f] ::= "6")  :=  MV([1-9a-f] ::= "6")  :=  MV([0-9] ::= "6")  :=  MV([1-9] ::= "6")  :=  MV([0-7] ::= "6")  :=  MV([1-7] ::= "6")  :=  6
MV([0-9a-z] ::= "7")  :=  MV([1-9a-z] ::= "7")  :=  MV([0-9a-f] ::= "7")  :=  MV([1-9a-f] ::= "7")  :=  MV([0-9] ::= "7")  :=  MV([1-9] ::= "7")  :=  MV([0-7] ::= "7")  :=  MV([1-7] ::= "7")  :=  7
MV([0-9a-z] ::= "8")  :=  MV([1-9a-z] ::= "8")  :=  MV([0-9a-f] ::= "8")  :=  MV([1-9a-f] ::= "8")  :=  MV([0-9] ::= "8")  :=  MV([1-9] ::= "8")  :=  8
MV([0-9a-z] ::= "9")  :=  MV([1-9a-z] ::= "9")  :=  MV([0-9a-f] ::= "9")  :=  MV([1-9a-f] ::= "9")  :=  MV([0-9] ::= "9")  :=  MV([1-9] ::= "9")  :=  9
MV([0-9a-z] ::= "a")  :=  MV([1-9a-z] ::= "a")  :=  MV([0-9a-f] ::= "a")  :=  MV([1-9a-f] ::= "a")  :=  10
MV([0-9a-z] ::= "b")  :=  MV([1-9a-z] ::= "b")  :=  MV([0-9a-f] ::= "b")  :=  MV([1-9a-f] ::= "b")  :=  11
MV([0-9a-z] ::= "c")  :=  MV([1-9a-z] ::= "c")  :=  MV([0-9a-f] ::= "c")  :=  MV([1-9a-f] ::= "c")  :=  12
MV([0-9a-z] ::= "d")  :=  MV([1-9a-z] ::= "d")  :=  MV([0-9a-f] ::= "d")  :=  MV([1-9a-f] ::= "d")  :=  13
MV([0-9a-z] ::= "e")  :=  MV([1-9a-z] ::= "e")  :=  MV([0-9a-f] ::= "e")  :=  MV([1-9a-f] ::= "e")  :=  14
MV([0-9a-z] ::= "f")  :=  MV([1-9a-z] ::= "f")  :=  MV([0-9a-f] ::= "f")  :=  MV([1-9a-f] ::= "f")  :=  15
MV([0-9a-z] ::= "g")  :=  MV([1-9a-z] ::= "g")  :=  16
MV([0-9a-z] ::= "h")  :=  MV([1-9a-z] ::= "h")  :=  17
MV([0-9a-z] ::= "i")  :=  MV([1-9a-z] ::= "i")  :=  18
MV([0-9a-z] ::= "j")  :=  MV([1-9a-z] ::= "j")  :=  19
MV([0-9a-z] ::= "k")  :=  MV([1-9a-z] ::= "k")  :=  20
MV([0-9a-z] ::= "l")  :=  MV([1-9a-z] ::= "l")  :=  21
MV([0-9a-z] ::= "m")  :=  MV([1-9a-z] ::= "m")  :=  22
MV([0-9a-z] ::= "n")  :=  MV([1-9a-z] ::= "n")  :=  23
MV([0-9a-z] ::= "o")  :=  MV([1-9a-z] ::= "o")  :=  24
MV([0-9a-z] ::= "p")  :=  MV([1-9a-z] ::= "p")  :=  25
MV([0-9a-z] ::= "q")  :=  MV([1-9a-z] ::= "q")  :=  26
MV([0-9a-z] ::= "r")  :=  MV([1-9a-z] ::= "r")  :=  27
MV([0-9a-z] ::= "s")  :=  MV([1-9a-z] ::= "s")  :=  28
MV([0-9a-z] ::= "t")  :=  MV([1-9a-z] ::= "t")  :=  29
MV([0-9a-z] ::= "u")  :=  MV([1-9a-z] ::= "u")  :=  30
MV([0-9a-z] ::= "v")  :=  MV([1-9a-z] ::= "v")  :=  31
MV([0-9a-z] ::= "w")  :=  MV([1-9a-z] ::= "w")  :=  32
MV([0-9a-z] ::= "x")  :=  MV([1-9a-z] ::= "x")  :=  33
MV([0-9a-z] ::= "y")  :=  MV([1-9a-z] ::= "y")  :=  34
MV([0-9a-z] ::= "z")  :=  MV([1-9a-z] ::= "z")  :=  35

No edits are needed for the syntactic grammar, since NonInteger is already there.

Imaginary Numbers

Imaginary numbers have many uses (the term “imaginary” is most unfortunate, since they no more imaginary than “real” numbers), but they’re most commonly recognized as square roots of negative numbers. For example, the square root of −4 is 2i, where i is the unique imaginary number whose square is −1. (Thus 2i 2i = 4i2 = 4 −1 = −4.)

The lexical syntax of an imaginary number is an integer or a float, appended with i.

let a = 6.283_185i;
let b = -2i;

Rational Numbers

Rational numbers are pairs of integers that represent ratios. Rational numbers are multiplied and divided more accurately than floating-point numbers (at the cost of a slight performance hit).

The syntax of a rational number is two integer literals separated by ~, U+007E TILDE, without any whitespace.

let a = -2~10;
let b = 22~7;
let c = \zm~\b111;    \ mixing bases is allowed
let c = 3_500~10_000; \ numeric separators are allowed

The only caveat is that the integer literal after ~ must be positive (cannot start with - and must contain a non-zero digit). The following are lexical errors: 42~0, 2~-12.

When computed, rational numbers representing equal ratios will be equal. For example, 1~6 and 2~12 have the same Rational Value (RV).