Merge pull request 'hex and binary numbers' (#40) from hex-and-binary-numbers into main
Reviewed-on: #40
This commit is contained in:
commit
4c15526d1b
|
|
@ -106,11 +106,21 @@ export class Compiler {
|
|||
|
||||
switch (node.type.id) {
|
||||
case terms.Number:
|
||||
const number = Number(value)
|
||||
if (Number.isNaN(number))
|
||||
// Handle sign prefix for hex and binary literals
|
||||
// Number() doesn't parse '-0xFF' or '+0xFF' correctly
|
||||
let numberValue: number
|
||||
if (value.startsWith('-') && (value.includes('0x') || value.includes('0b'))) {
|
||||
numberValue = -Number(value.slice(1))
|
||||
} else if (value.startsWith('+') && (value.includes('0x') || value.includes('0b'))) {
|
||||
numberValue = Number(value.slice(1))
|
||||
} else {
|
||||
numberValue = Number(value)
|
||||
}
|
||||
|
||||
if (Number.isNaN(numberValue))
|
||||
throw new CompilerError(`Invalid number literal: ${value}`, node.from, node.to)
|
||||
|
||||
return [[`PUSH`, number]]
|
||||
return [[`PUSH`, numberValue]]
|
||||
|
||||
case terms.String: {
|
||||
const { parts, hasInterpolation } = getStringParts(node, input)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,44 @@
|
|||
import { describe } from 'bun:test'
|
||||
import { expect, test } from 'bun:test'
|
||||
|
||||
describe('number literals', () => {
|
||||
test('binary literals', () => {
|
||||
expect('0b110').toEvaluateTo(6)
|
||||
expect('0b1010').toEvaluateTo(10)
|
||||
expect('0b11111111').toEvaluateTo(255)
|
||||
expect('0b0').toEvaluateTo(0)
|
||||
expect('0b1').toEvaluateTo(1)
|
||||
})
|
||||
|
||||
test('hex literals', () => {
|
||||
expect('0xdeadbeef').toEvaluateTo(0xdeadbeef)
|
||||
expect('0xdeadbeef').toEvaluateTo(3735928559)
|
||||
expect('0xFF').toEvaluateTo(255)
|
||||
expect('0xff').toEvaluateTo(255)
|
||||
expect('0x10').toEvaluateTo(16)
|
||||
expect('0x0').toEvaluateTo(0)
|
||||
expect('0xABCDEF').toEvaluateTo(0xabcdef)
|
||||
})
|
||||
|
||||
test('decimal literals still work', () => {
|
||||
expect('42').toEvaluateTo(42)
|
||||
expect('3.14').toEvaluateTo(3.14)
|
||||
expect('0').toEvaluateTo(0)
|
||||
expect('999999').toEvaluateTo(999999)
|
||||
})
|
||||
|
||||
test('negative hex and binary', () => {
|
||||
expect('-0xFF').toEvaluateTo(-255)
|
||||
expect('-0b1010').toEvaluateTo(-10)
|
||||
})
|
||||
|
||||
test('positive prefix', () => {
|
||||
expect('+0xFF').toEvaluateTo(255)
|
||||
expect('+0b110').toEvaluateTo(6)
|
||||
expect('+42').toEvaluateTo(42)
|
||||
})
|
||||
})
|
||||
|
||||
describe('array literals', () => {
|
||||
test('work with numbers', () => {
|
||||
expect('[1 2 3]').toEvaluateTo([1, 2, 3])
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@
|
|||
|
||||
StringFragment { !['\\$]+ }
|
||||
NamedArgPrefix { $[a-z] $[a-z0-9-]* "=" }
|
||||
Number { ("-" | "+")? $[0-9]+ ("_"? $[0-9]+)* ('.' $[0-9]+ ("_"? $[0-9]+)*)? }
|
||||
Number {
|
||||
("-" | "+")? "0x" $[0-9a-fA-F]+ |
|
||||
("-" | "+")? "0b" $[01]+ |
|
||||
("-" | "+")? $[0-9]+ ("_"? $[0-9]+)* ('.' $[0-9]+ ("_"? $[0-9]+)*)?
|
||||
}
|
||||
Boolean { "true" | "false" }
|
||||
newlineOrSemicolon { "\n" | ";" }
|
||||
eof { @eof }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const parser = LRParser.deserialize({
|
|||
propSources: [highlighting],
|
||||
skippedNodes: [0,25],
|
||||
repeatNodeCount: 12,
|
||||
tokenData: "Cx~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O(e!O!P#{!P!Q+e!Q![)S![!]4Q!]!^%T!^!}#{!}#O4k#O#P6a#P#Q6f#Q#R#{#R#S7P#S#T#{#T#Y7j#Y#Z9U#Z#b7j#b#c>r#c#f7j#f#g?u#g#h7j#h#i@x#i#o7j#o#p#{#p#qCY#q;'S#{;'S;=`$d<%l~#{~O#{~~CsS$QUzSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUzS!zYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UzS#QQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZiYzSOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mSiYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#V~~'aO#T~U'hUzS#PQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUzS#_QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWzSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)Z[zSsQOt#{uw#{x!O#{!O!P*P!P!Q#{!Q![)S![#O#{#P#R#{#R#S(e#S;'S#{;'S;=`$d<%lO#{U*UWzSOt#{uw#{x!Q#{!Q![*n![#O#{#P;'S#{;'S;=`$d<%lO#{U*uYzSsQOt#{uw#{x!Q#{!Q![*n![#O#{#P#R#{#R#S*P#S;'S#{;'S;=`$d<%lO#{U+jWzSOt#{uw#{x!P#{!P!Q,S!Q#O#{#P;'S#{;'S;=`$d<%lO#{U,X^zSOY-TYZ#{Zt-Ttu.Wuw-Twx.Wx!P-T!P!Q#{!Q!}-T!}#O2y#O#P0f#P;'S-T;'S;=`3z<%lO-TU-[^zS!bQOY-TYZ#{Zt-Ttu.Wuw-Twx.Wx!P-T!P!Q0{!Q!}-T!}#O2y#O#P0f#P;'S-T;'S;=`3z<%lO-TQ.]X!bQOY.WZ!P.W!P!Q.x!Q!}.W!}#O/g#O#P0f#P;'S.W;'S;=`0u<%lO.WQ.{P!P!Q/OQ/TU!bQ#Z#[/O#]#^/O#a#b/O#g#h/O#i#j/O#m#n/OQ/jVOY/gZ#O/g#O#P0P#P#Q.W#Q;'S/g;'S;=`0`<%lO/gQ0SSOY/gZ;'S/g;'S;=`0`<%lO/gQ0cP;=`<%l/gQ0iSOY.WZ;'S.W;'S;=`0u<%lO.WQ0xP;=`<%l.WU1QWzSOt#{uw#{x!P#{!P!Q1j!Q#O#{#P;'S#{;'S;=`$d<%lO#{U1qbzS!bQOt#{uw#{x#O#{#P#Z#{#Z#[1j#[#]#{#]#^1j#^#a#{#a#b1j#b#g#{#g#h1j#h#i#{#i#j1j#j#m#{#m#n1j#n;'S#{;'S;=`$d<%lO#{U3O[zSOY2yYZ#{Zt2ytu/guw2ywx/gx#O2y#O#P0P#P#Q-T#Q;'S2y;'S;=`3t<%lO2yU3wP;=`<%l2yU3}P;=`<%l-TU4XUzS!PQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U4rW#aQzSOt#{uw#{x!_#{!_!`5[!`#O#{#P;'S#{;'S;=`$d<%lO#{U5aVzSOt#{uw#{x#O#{#P#Q5v#Q;'S#{;'S;=`$d<%lO#{U5}U#`QzSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~6fO#W~U6mU#bQzSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7WUzS!WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7o^zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#o7j#o;'S#{;'S;=`$d<%lO#{U8rUxQzSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9Z_zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#U:Y#U#o7j#o;'S#{;'S;=`$d<%lO#{U:_`zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#`7j#`#a;a#a#o7j#o;'S#{;'S;=`$d<%lO#{U;f`zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#g7j#g#h<h#h#o7j#o;'S#{;'S;=`$d<%lO#{U<m`zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#X7j#X#Y=o#Y#o7j#o;'S#{;'S;=`$d<%lO#{U=v^}QzSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#o7j#o;'S#{;'S;=`$d<%lO#{^>y^#XWzSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#o7j#o;'S#{;'S;=`$d<%lO#{^?|^#ZWzSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#o7j#o;'S#{;'S;=`$d<%lO#{^AP`#YWzSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#f7j#f#gBR#g#o7j#o;'S#{;'S;=`$d<%lO#{UBW`zSOt#{uw#{x}#{}!O7j!O!Q#{!Q![7j![!_#{!_!`8k!`#O#{#P#T#{#T#i7j#i#j<h#j#o7j#o;'S#{;'S;=`$d<%lO#{UCaUlQzSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~CxO#c~",
|
||||
tokenData: "IS~R}OX$OXY$mYZ%WZp$Opq$mqs$Ost%qtu'Yuw$Owx'_xy'dyz'}z{$O{|(h|}$O}!O(h!O!P$O!P!Q0o!Q!R)Y!R![+w![!]9[!]!^%W!^!}$O!}#O9u#O#P;k#P#Q;p#Q#R$O#R#S<Z#S#T$O#T#Y<t#Y#Z>`#Z#b<t#b#cC|#c#f<t#f#gEP#g#h<t#h#iFS#i#o<t#o#p$O#p#qHd#q;'S$O;'S;=`$g<%l~$O~O$O~~H}S$TUzSOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OS$jP;=`<%l$O^$tUzS!zYOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU%_UzS#QQOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$O^%xZiYzSOY%qYZ$OZt%qtu&kuw%qwx&kx#O%q#O#P&k#P;'S%q;'S;=`'S<%lO%qY&pSiYOY&kZ;'S&k;'S;=`&|<%lO&kY'PP;=`<%l&k^'VP;=`<%l%q~'_O#V~~'dO#T~U'kUzS#PQOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU(UUzS#_QOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU(mXzSOt$Ouw$Ox!Q$O!Q!R)Y!R![+w![#O$O#P;'S$O;'S;=`$g<%lO$OU)a`zSsQOt$Ouw$Ox!O$O!O!P*c!P!Q$O!Q![+w![#O$O#P#R$O#R#S,t#S#U$O#U#V-c#V#l$O#l#m.w#m;'S$O;'S;=`$g<%lO$OU*hWzSOt$Ouw$Ox!Q$O!Q![+Q![#O$O#P;'S$O;'S;=`$g<%lO$OU+XYzSsQOt$Ouw$Ox!Q$O!Q![+Q![#O$O#P#R$O#R#S*c#S;'S$O;'S;=`$g<%lO$OU,O[zSsQOt$Ouw$Ox!O$O!O!P*c!P!Q$O!Q![+w![#O$O#P#R$O#R#S,t#S;'S$O;'S;=`$g<%lO$OU,yWzSOt$Ouw$Ox!Q$O!Q![+w![#O$O#P;'S$O;'S;=`$g<%lO$OU-hXzSOt$Ouw$Ox!Q$O!Q!R.T!R!S.T!S#O$O#P;'S$O;'S;=`$g<%lO$OU.[XzSsQOt$Ouw$Ox!Q$O!Q!R.T!R!S.T!S#O$O#P;'S$O;'S;=`$g<%lO$OU.|[zSOt$Ouw$Ox!Q$O!Q![/r![!c$O!c!i/r!i#O$O#P#T$O#T#Z/r#Z;'S$O;'S;=`$g<%lO$OU/y[zSsQOt$Ouw$Ox!Q$O!Q![/r![!c$O!c!i/r!i#O$O#P#T$O#T#Z/r#Z;'S$O;'S;=`$g<%lO$OU0tWzSOt$Ouw$Ox!P$O!P!Q1^!Q#O$O#P;'S$O;'S;=`$g<%lO$OU1c^zSOY2_YZ$OZt2_tu3buw2_wx3bx!P2_!P!Q$O!Q!}2_!}#O8T#O#P5p#P;'S2_;'S;=`9U<%lO2_U2f^zS!bQOY2_YZ$OZt2_tu3buw2_wx3bx!P2_!P!Q6V!Q!}2_!}#O8T#O#P5p#P;'S2_;'S;=`9U<%lO2_Q3gX!bQOY3bZ!P3b!P!Q4S!Q!}3b!}#O4q#O#P5p#P;'S3b;'S;=`6P<%lO3bQ4VP!P!Q4YQ4_U!bQ#Z#[4Y#]#^4Y#a#b4Y#g#h4Y#i#j4Y#m#n4YQ4tVOY4qZ#O4q#O#P5Z#P#Q3b#Q;'S4q;'S;=`5j<%lO4qQ5^SOY4qZ;'S4q;'S;=`5j<%lO4qQ5mP;=`<%l4qQ5sSOY3bZ;'S3b;'S;=`6P<%lO3bQ6SP;=`<%l3bU6[WzSOt$Ouw$Ox!P$O!P!Q6t!Q#O$O#P;'S$O;'S;=`$g<%lO$OU6{bzS!bQOt$Ouw$Ox#O$O#P#Z$O#Z#[6t#[#]$O#]#^6t#^#a$O#a#b6t#b#g$O#g#h6t#h#i$O#i#j6t#j#m$O#m#n6t#n;'S$O;'S;=`$g<%lO$OU8Y[zSOY8TYZ$OZt8Ttu4quw8Twx4qx#O8T#O#P5Z#P#Q2_#Q;'S8T;'S;=`9O<%lO8TU9RP;=`<%l8TU9XP;=`<%l2_U9cUzS!PQOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU9|W#aQzSOt$Ouw$Ox!_$O!_!`:f!`#O$O#P;'S$O;'S;=`$g<%lO$OU:kVzSOt$Ouw$Ox#O$O#P#Q;Q#Q;'S$O;'S;=`$g<%lO$OU;XU#`QzSOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$O~;pO#W~U;wU#bQzSOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU<bUzS!WQOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU<y^zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#o<t#o;'S$O;'S;=`$g<%lO$OU=|UxQzSOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$OU>e_zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#U?d#U#o<t#o;'S$O;'S;=`$g<%lO$OU?i`zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#`<t#`#a@k#a#o<t#o;'S$O;'S;=`$g<%lO$OU@p`zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#g<t#g#hAr#h#o<t#o;'S$O;'S;=`$g<%lO$OUAw`zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#X<t#X#YBy#Y#o<t#o;'S$O;'S;=`$g<%lO$OUCQ^}QzSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#o<t#o;'S$O;'S;=`$g<%lO$O^DT^#XWzSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#o<t#o;'S$O;'S;=`$g<%lO$O^EW^#ZWzSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#o<t#o;'S$O;'S;=`$g<%lO$O^FZ`#YWzSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#f<t#f#gG]#g#o<t#o;'S$O;'S;=`$g<%lO$OUGb`zSOt$Ouw$Ox}$O}!O<t!O!Q$O!Q![<t![!_$O!_!`=u!`#O$O#P#T$O#T#i<t#i#jAr#j#o<t#o;'S$O;'S;=`$g<%lO$OUHkUlQzSOt$Ouw$Ox#O$O#P;'S$O;'S;=`$g<%lO$O~ISO#c~",
|
||||
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO#R~~", 11)],
|
||||
topRules: {"Program":[0,26]},
|
||||
specialized: [{term: 20, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 20, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
|
||||
|
|
|
|||
|
|
@ -2,6 +2,65 @@ import { expect, describe, test } from 'bun:test'
|
|||
|
||||
import '../shrimp.grammar' // Importing this so changes cause it to retest!
|
||||
|
||||
describe('number literals', () => {
|
||||
test('binary numbers', () => {
|
||||
expect('0b110').toMatchTree(`
|
||||
Number 0b110
|
||||
`)
|
||||
})
|
||||
|
||||
test('hex numbers', () => {
|
||||
expect('0xdeadbeef').toMatchTree(`
|
||||
Number 0xdeadbeef
|
||||
`)
|
||||
})
|
||||
|
||||
test('hex numbers uppercase', () => {
|
||||
expect('0xFF').toMatchTree(`
|
||||
Number 0xFF
|
||||
`)
|
||||
})
|
||||
|
||||
test('decimal numbers still work', () => {
|
||||
expect('42').toMatchTree(`
|
||||
Number 42
|
||||
`)
|
||||
})
|
||||
|
||||
test('negative binary', () => {
|
||||
expect('-0b110').toMatchTree(`
|
||||
Number -0b110
|
||||
`)
|
||||
})
|
||||
|
||||
test('negative hex', () => {
|
||||
expect('-0xFF').toMatchTree(`
|
||||
Number -0xFF
|
||||
`)
|
||||
})
|
||||
|
||||
test('positive prefix binary', () => {
|
||||
expect('+0b110').toMatchTree(`
|
||||
Number +0b110
|
||||
`)
|
||||
})
|
||||
|
||||
test('positive prefix hex', () => {
|
||||
expect('+0xFF').toMatchTree(`
|
||||
Number +0xFF
|
||||
`)
|
||||
})
|
||||
|
||||
test('hex and binary in arrays', () => {
|
||||
expect('[0xFF 0b110 42]').toMatchTree(`
|
||||
Array
|
||||
Number 0xFF
|
||||
Number 0b110
|
||||
Number 42
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('array literals', () => {
|
||||
test('work with numbers', () => {
|
||||
expect('[1 2 3]').toMatchTree(`
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user