LightAndLight / ipso

A functional scripting language.
https://ipso.dev
16 stars 1 forks source link

Number parsing builtins #393

Closed LightAndLight closed 1 year ago

LightAndLight commented 1 year ago

branch


I often find myself converting strings to numbers.

# Parses strings that match: `-?(0b)?[01]+`
int.parseBin : String -> (| Some : Int, None : () |)

# Parses strings that match: `-?(0o)?[0-7]+`
int.parseOct : String -> (| Some : Int, None : () |)

# Parses strings that match: `-?[0-9]+`
int.parseDec : String -> (| Some : Int, None : () |)

# Parses strings that match: `-?(0x)?[0-9a-fA-F]+`
int.parseHex : String -> (| Some : Int, None : () |)

Out of scope (see #413) (kept here for history)

And from https://github.com/LightAndLight/ipso/issues/393#issuecomment-1558267704:

# int.printBin 5 == "101"
# int.printBin -5 == "-101"
int.printBin : Int -> String

# int.printOct 10 == "12"
# int.printOct -10 == "-12"
int.printOct : Int -> String

# int.printDec 15 == "15"
# int.printDec -15 == "-15"
int.printDec : Int -> String

# int.printDec 30 == "1e"
# int.printDec -30 == "-1e"
int.printHex : Int -> String

And some base-generic functions:

int.binary : Array Char
int.octal : Array Char
int.decimal : Array Char
int.hexLower : Array Char
int.hexUpper : Array Char

int.printBase : Array Char -> Int -> String
int.printBase base = int.printBasePrefixed base ""

int.printBasePrefixed : Array Char -> String -> Int -> String
int.printBasePrefixed base prefix n =
  case int.toBase base n of
    { negative, value } -> "${if negative then "-" else ""}$prefix$value"

int.toBase : Array Char -> Int -> { negative : Bool, value : String }
LightAndLight commented 1 year ago

Should all the parsing functions allow an optional leading - for negative numbers?

LightAndLight commented 1 year ago

Should all the parsing functions allow an optional leading - for negative numbers?

I think having corresponding printing functions would ground this question. If printHex : Int -> String can print negative numbers (i.e. -0xFFF), then parseHex should successfully parse negative numbers.

LightAndLight commented 1 year ago

I'm a bit skeptical about the parsers accepting an optional leading prefix (0b, 0o, 0x). These aren't actually a feature of the counting systems; they're syntactic conventions. Would it be too much hassle for the user to strip these prefixes before calling the parsing function?

LightAndLight commented 1 year ago

What do other languages do?

Ruby

Parsing

String#to_i

Defaults to base 10. User can provide a base between 2 and 36 (inclusive). Base 0 means "infer base using prefix" like 0x,0o, and0b. Otherwise, base prefixes are allowed when then they match the specified base (i.e."0b101".to_i 2` succeeds). Parses negative numbers.

Printing

Integer#to_s

Defaults to base 10. User can provide a base between 2 and 36 (inclusive). Does not include a base prefix.

Python

Parsing

int

Defaults to base 10. User can provide a base between 2 and 36 (inclusive). Base 0 means "infer base using prefix" like 0x,0o, and0b. Otherwise, base prefixes are allowed when then they match the specified base (i.e.int("0b101", 2)` succeeds). Parses negative numbers.

Printing

LightAndLight commented 1 year ago

I don't know whether or not it would be more convenient to have the printX functions add the base prefix. I'll leave it off, and let users add it with int.printBasePrefixed base basePrefix. Later on, if I find that most use cases required the base prefix, then I could flip it around: printX adds the base prefix and int.printBase base prints without it.

LightAndLight commented 1 year ago

I'm a bit skeptical about the parsers accepting an optional leading prefix (0b, 0o, 0x). These aren't actually a feature of the counting systems; they're syntactic conventions. Would it be too much hassle for the user to strip these prefixes before calling the parsing function?

I'll make the parsing functions accept these prefixes for "least surprise" reasons. Being a little more liberal with the string inputs (where it doesn't sacrifice correctness) seems like a good thing.

LightAndLight commented 1 year ago

In the interest of keeping this issue small, I've factored out the printing functions into #413. Number parsing is much more useful to me right now.

LightAndLight commented 1 year ago

I've also left out the panicking versions:

int.parseHex! : String -> Int
int.parseDec! : String -> Int
int.parseOct! : String -> Int
int.parseBin! : String -> Int