Skip to content

Commit b484467

Browse files
authored
Merge pull request #1929 from arturo-lang/add-support-for-literal-integers-in-different-bases
Add parsing support for `:integer` literals in different bases
2 parents 7158acf + f1345c3 commit b484467

File tree

3 files changed

+73
-22
lines changed

3 files changed

+73
-22
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
238238
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
239239
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
240240
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
241-
SOFTWARE.
241+
SOFTWARE.

src/helpers/strings.nim

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,12 @@ func isWhitespace*(s: string): bool =
224224
if s.len == 0: return false
225225
for c in s:
226226
if c notin Whitespace: return false
227-
return true
227+
return true
228+
229+
func parseNumFromString*(s: string, base: int): int =
230+
case base:
231+
of 2: return parseBinInt(s)
232+
of 8: return parseOctInt(s)
233+
of 10: return parseInt(s)
234+
of 16: return parseHexInt(s)
235+
else: raise newException(ValueError, "Invalid base")

src/vm/parse.nim

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
##
1717
## The main entry point is `doParse`.
1818

19-
# TODO(VM/parser) General cleanup needed
20-
# There are various pieces of commented-out code that make the final result pretty much illegible. Let's clean this up.
19+
# TODO(VM/parser) Enhance/rewrite the whole file
20+
# - The parser is currently a bit of a mess
21+
# - It should be rewritten to be cleaner & more efficient
22+
# - It should also be more error-aware
2123
# labels: vm, parser, cleanup
2224

2325
#=======================================
@@ -30,6 +32,8 @@ import strutils, tables, unicode
3032
import vm/[errors, values/value]
3133
import vm/values/custom/[vquantity, vsymbol]
3234

35+
import helpers/strings
36+
3337
#=======================================
3438
# Types
3539
#=======================================
@@ -513,36 +517,75 @@ template parseIdentifier(p: var Parser, alsoAddCurrent: bool) =
513517
inc(pos)
514518
p.bufpos = pos
515519

516-
template parseNumber(p: var Parser) =
520+
template parseNumber(p: var Parser, inPath: bool = false) =
517521
var pos = p.bufpos
518-
while p.buf[pos] in Digits:
519-
add(p.value, p.buf[pos])
520-
inc(pos)
522+
var alreadyParsedNumber = false
521523

522-
var hasDot{.inject.} = false
524+
when not inPath:
525+
var numBase = 10
526+
if p.buf[pos] == '0':
527+
add(p.value, p.buf[pos])
528+
var numAllowedChars = {'0'..'9'}
529+
530+
if p.buf[pos+1] in {'x'}:
531+
numBase = 16
532+
numAllowedChars = {'0'..'9', 'a'..'f', 'A'..'F'}
533+
add(p.value, p.buf[pos+1])
534+
inc(pos, 2)
535+
elif p.buf[pos+1] in {'b'}:
536+
numBase = 2
537+
numAllowedChars = {'0','1'}
538+
add(p.value, p.buf[pos+1])
539+
inc(pos, 2)
540+
elif p.buf[pos+1] in {'o'}:
541+
numBase = 8
542+
numAllowedChars = {'0'..'7'}
543+
add(p.value, p.buf[pos+1])
544+
inc(pos, 2)
545+
else:
546+
numAllowedChars = {}
547+
548+
if p.buf[pos] in numAllowedChars:
549+
while p.buf[pos] in numAllowedChars:
550+
add(p.value, p.buf[pos])
551+
inc(pos)
523552

524-
if p.buf[pos] == Dot and p.buf[pos+1] in Digits:
525-
hasDot = true
553+
p.value = $(parseNumFromString(p.value, numBase))
554+
p.bufpos = pos
555+
alreadyParsedNumber = true
556+
else:
557+
pos = p.bufpos
558+
p.value = ""
526559

527-
add(p.value, Dot)
528-
inc(pos)
560+
var hasDot{.inject.} = false
529561

562+
if likely(not alreadyParsedNumber):
530563
while p.buf[pos] in Digits:
531564
add(p.value, p.buf[pos])
532565
inc(pos)
533566

534-
if p.buf[pos] == Dot:
535-
if p.buf[pos+1] in Digits:
536-
add(p.value, Dot)
567+
if p.buf[pos] == Dot and p.buf[pos+1] in Digits:
568+
hasDot = true
569+
570+
add(p.value, Dot)
571+
inc(pos)
572+
573+
while p.buf[pos] in Digits:
574+
add(p.value, p.buf[pos])
537575
inc(pos)
538-
while p.buf[pos] in Digits:
539-
add(p.value, p.buf[pos])
576+
577+
if p.buf[pos] == Dot:
578+
if p.buf[pos+1] in Digits:
579+
add(p.value, Dot)
540580
inc(pos)
541-
542-
if p.buf[pos] in {'+','-'}:
543-
while p.buf[pos] in SemVerExtra:
581+
while p.buf[pos] in Digits:
544582
add(p.value, p.buf[pos])
545583
inc(pos)
584+
585+
if p.buf[pos] in {'+','-'}:
586+
while p.buf[pos] in SemVerExtra:
587+
add(p.value, p.buf[pos])
588+
inc(pos)
546589

547590
p.bufpos = pos
548591

@@ -806,7 +849,7 @@ template parsePath(p: var Parser, root: Value, curLevel: int, asLiteral: bool =
806849
p.values[^1].add(newLiteral(p.value))
807850
of PermittedNumbers_Start:
808851
setLen(p.value, 0)
809-
parseNumber(p)
852+
parseNumber(p, inPath=true)
810853
if hasDot: p.values[^1].add(newFloating(p.value))
811854
else: p.values[^1].add(newInteger(p.value))
812855
of LBracket:

0 commit comments

Comments
 (0)