failing single line if test #5

Merged
probablycorey merged 3 commits from single-line-if into main 2025-10-27 18:31:48 +00:00
6 changed files with 31 additions and 14 deletions

View File

@ -303,7 +303,8 @@ export class Compiler {
return instructions
}
case terms.ThenBlock: {
case terms.ThenBlock:
case terms.SingleLineThenBlock: {
const instructions = getAllChildren(node)
.map((child) => this.#compileNode(child, input))
.flat()
@ -468,7 +469,11 @@ export class Compiler {
}
default:
throw new CompilerError(`Unsupported syntax node: ${node.type.name}`, node.from, node.to)
throw new CompilerError(
`Compiler doesn't know how to handle a "${node.type.name}" node.`,
node.from,
node.to
)
}
}
}

View File

@ -139,6 +139,10 @@ describe('compiler', () => {
scattered
end`).toEvaluateTo('dwarf')
})
test('single line if', () => {
expect(`if 3 < 9: shire end`).toEvaluateTo('shire')
})
})
describe('errors', () => {

View File

@ -105,7 +105,7 @@ IfExpr {
}
singleLineIf {
@specialize[@name=keyword]<Identifier, "if"> (ConditionalOp | expression) colon ThenBlock { consumeToTerminator }
@specialize[@name=keyword]<Identifier, "if"> (ConditionalOp | expression) colon SingleLineThenBlock @specialize[@name=keyword]<Identifier, "end">
}
multilineIf {
@ -124,6 +124,10 @@ ThenBlock {
block
}
SingleLineThenBlock {
consumeToTerminator
}
ConditionalOp {
expression Eq expression |
expression Neq expression |

View File

@ -41,6 +41,7 @@ export const
NamedArg = 40,
NamedArgPrefix = 41,
IfExpr = 43,
SingleLineThenBlock = 45,
ThenBlock = 46,
ElseIfExpr = 47,
ElseExpr = 49,

View File

@ -7,10 +7,10 @@ import {highlighting} from "./highlight"
const spec_Identifier = {__proto__:null,do:52, end:58, null:74, if:88, elseif:96, else:100}
export const parser = LRParser.deserialize({
version: 14,
states: ".jQYQbOOO#[QcO'#CrO$UQRO'#CsO$dQcO'#DnO${QbO'#DtOOQ`'#Cu'#CuO%TQbO'#CqO%uOSO'#CzOOQa'#Dr'#DrO&TOpO'#DSO&YQcO'#DqOOQ`'#Do'#DoO&qQbO'#DnO'PQbO'#EROOQ`'#DX'#DXO'nQRO'#DaOOQ`'#Dn'#DnO'sQQO'#DmOOQ`'#Dm'#DmOOQ`'#Db'#DbQYQbOOOOQa'#Dq'#DqOOQ`'#Cp'#CpO'{QbO'#DUOOQ`'#Dp'#DpOOQ`'#Dc'#DcO(VQbO,59ZO'PQbO,59_O'PQbO,59_OOQ`'#Dd'#DdO(sQbO'#CwO({QQO,5:`O)lQRO'#CsO)|QRO,59]O*_QRO,59]O*YQQO,59]O+YQQO,59]O+bQbO'#C|O+jQWO'#C}OOOO'#Dz'#DzOOOO'#Df'#DfO,OOSO,59fOOQa,59f,59fO,^O`O,59nO,cQbO'#DgO,hQbO,59YO,yQRO,5:mO-QQQO,5:mO-VQbO,59{OOQ`,5:X,5:XOOQ`-E7`-E7`OOQ`,59p,59pOOQ`-E7a-E7aOOQa1G.y1G.yO-aQcO1G.yOOQ`-E7b-E7bO-{QbO1G/zO'PQbO,59`O'PQbO,59`OOQa1G.w1G.wOOOO,59h,59hOOOO,59i,59iOOOO-E7d-E7dOOQa1G/Q1G/QOOQa1G/Y1G/YO!TQbO'#CrOOQ`,5:R,5:ROOQ`-E7e-E7eO.YQbO1G0XOOQ`1G/g1G/gO.gQbO7+%fO.lQbO7+%gOOQO1G.z1G.zO.yQRO1G.zOOQ`'#DZ'#DZOOQ`7+%s7+%sO/TQbO7+%tOOQ`<<IQ<<IQO/hQQO'#DeO/mQbO'#DwO0QQbO<<IROOQ`'#D['#D[O0VQbO<<I`OOQ`,5:P,5:POOQ`-E7c-E7cOOQ`AN>mAN>mO'PQbO'#D]OOQ`'#Dh'#DhO0bQbOAN>zO0mQQO'#D_OOQ`AN>zAN>zO0rQbOAN>zO0wQRO,59wO1OQQO,59wOOQ`-E7f-E7fOOQ`G24fG24fO1TQbOG24fO1YQQO,59yO1_QQO1G/cOOQ`LD*QLD*QO.lQbO1G/eO/TQbO7+$}OOQ`7+%P7+%POOQ`<<Hi<<Hi",
stateData: "1g~O!_OS!`OS~O]PO^_O_WO`XOjSOrWOsWOtWOuWO|]O!gUO!jbO!mVO~O]eO_WO`XOjSOrWOsWOtWOuWOwfOygO!gUO!mVOzfX!jfX!wfX!lfXmfX~OP!eXQ!eXR!eXS!eXT!eXU!eXV!eXW!eXX!eXY!eXZ!eX[!eX~P!TOPkOQkORlOSlO~OPkOQkORlOSlO!j!bX!w!bXm!bX~O^mOlkP~O]PO_WO`XOjSOrWOsWOtWOuWO!gUO!mVO~OowO!mzO!ouO!pvO~O!t{O~OP!eXQ!eXR!eXS!eX!j!bX!w!bXm!bX~Oz|O!j!bX!w!bXm!bX~O]eO_WO`XOrWOsWOtWOuWO!gUO!mVO~OV!QO~O!j!RO!w!RO~OjSOw!TO~P'POjSOwfOygOzca!jca!wca!lcamca~P'PO^mOlkX~Ol!YO~OT![OU![OV!ZOW!ZOX!ZOY!ZOZ!ZO[!ZO~OPkOQkORlOSlO~P)QOPkOQkORlOSlO!l!]O~O!l!]OP!eXQ!eXR!eXS!eXT!eXU!eXV!eXW!eXX!eXY!eXZ!eX[!eX~Oz|O!l!]O~O]!^O!gUO~O!m!_O!o!_O!p!_O!q!_O!r!_O!s!_O~OowO!m!aO!ouO!pvO~O]!bO~O]!cO~Oz|O!jba!wba!lbamba~Ol!fO~P)QOl!fO~O^_O|]O~P%TOPkOQkORgiSgi!jgi!wgi!lgimgi~O^_O|]O!j!iO~P%TO^_O|]O!j!nO~P%TOm!oO~O^_O|]Om!kP~P%TO!lhilhi~P)QO^_O|]Om!kP!Q!kP!S!kP~P%TO!j!uO~O^_O|]Om!kX!Q!kX!S!kX~P%TOm!wO~Om!|O!Q!xO!S!{O~Om#RO!Q!xO!S!{O~Ol#TO~Om#RO~Ol#UO~P)QOl#UO~Om#VO~O!j#WO~O!j#XO~Ort~",
goto: "+r!wPPPPPPPPPPPPPPPPPP!x#X#g#l#X$W$m$yP%bPP%eP%|%|PPPP&QP#gPP&kP&w&z'TP'XP&k'_'e'l'r'{(R(YPPPP(`(d(x)[)a*[P*w*wP+YPP+bPPPPPP+f+fd`Od!Q!Y!f!i!n!q#W#XRsUiZOUd|!Q!Y!f!i!n!q#W#XVhPj!czWOPU]dgjkl!Q!Y!Z![!c!f!i!n!q!x#W#XR!^udROd!Q!Y!f!i!n!q#W#XQqUQ!VkR!WlQsUQ!P]Q!j![R#P!xd`Od!Q!Y!f!i!n!q#W#XUfPj!cQsUR!TgRoS{WOPU]dgjkl!Q!Y!Z![!c!f!i!n!q!x#W#XTwVydYOd!Q!Y!f!i!n!q#W#XgePU]gjkl!Z![!c!xe`Od!Q!Y!f!i!n!q#W#XR!m!fQ!t!nQ#Y#WR#Z#XT!y!t!zQ!}!tR#S!zQdOR!SdSjP!cR!UjQnSR!XnW!q!i!n#W#XR!v!qQyVR!`yS}[tR!e}Q!z!tR#Q!zTcOdSaOdQ!g!QQ!h!YQ!l!fZ!p!i!n!q#W#Xd[Od!Q!Y!f!i!n!q#W#XQtUR!d|ViPj!cdQOd!Q!Y!f!i!n!q#W#XUfPj!cQpUQ!O]Q!TgQ!VkQ!WlQ!j!ZQ!k![R#O!xdYOd!Q!Y!f!i!n!q#W#XdeP]gjkl!Z![!c!xRrUoTOPUdgj!Q!Y!c!f!i!n!q#W#XQ!r!iV!s!n#W#XTxVye^Od!Q!Y!f!i!n!q#W#X",
nodeNames: "⚠ Star Slash Plus Minus And Or Eq Neq Lt Lte Gt Gte Identifier AssignableIdentifier Word IdentifierBeforeDot Program PipeExpr FunctionCall PositionalArg ParenExpr FunctionCallOrIdentifier BinOp ConditionalOp FunctionDef keyword Params colon keyword String StringFragment Interpolation EscapeSeq Number Boolean Regex Null DotGet Underscore NamedArg NamedArgPrefix operator IfExpr keyword ThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword Assign",
states: ".pQYQbOOO#[QcO'#CrO$UQRO'#CsO$dQcO'#DnO${QbO'#DtOOQ`'#Cu'#CuO%TQbO'#CqO%uOSO'#CzOOQa'#Dr'#DrO&TOpO'#DSO&YQcO'#DqOOQ`'#Do'#DoO&qQbO'#DnO'PQbO'#EROOQ`'#DX'#DXO'nQRO'#DaOOQ`'#Dn'#DnO'sQQO'#DmOOQ`'#Dm'#DmOOQ`'#Db'#DbQYQbOOOOQa'#Dq'#DqOOQ`'#Cp'#CpO'{QbO'#DUOOQ`'#Dp'#DpOOQ`'#Dc'#DcO(VQbO,59ZO'PQbO,59_O'PQbO,59_OOQ`'#Dd'#DdO(sQbO'#CwO({QQO,5:`O)lQRO'#CsO)|QRO,59]O*_QRO,59]O*YQQO,59]O+YQQO,59]O+bQbO'#C|O+jQWO'#C}OOOO'#Dz'#DzOOOO'#Df'#DfO,OOSO,59fOOQa,59f,59fO,^O`O,59nO,cQbO'#DgO,hQbO,59YO,yQRO,5:mO-QQQO,5:mO-VQbO,59{OOQ`,5:X,5:XOOQ`-E7`-E7`OOQ`,59p,59pOOQ`-E7a-E7aOOQa1G.y1G.yO-aQcO1G.yOOQ`-E7b-E7bO-{QbO1G/zO'PQbO,59`O'PQbO,59`OOQa1G.w1G.wOOOO,59h,59hOOOO,59i,59iOOOO-E7d-E7dOOQa1G/Q1G/QOOQa1G/Y1G/YO!TQbO'#CrOOQ`,5:R,5:ROOQ`-E7e-E7eO.YQbO1G0XOOQ`1G/g1G/gO.gQbO7+%fO.lQbO7+%gOOQO1G.z1G.zO.yQRO1G.zOOQ`'#DZ'#DZO/TQbO7+%sO/YQbO7+%tOOQ`<<IQ<<IQO/mQQO'#DeO/rQbO'#DwO0VQbO<<IROOQ`<<I_<<I_OOQ`'#D['#D[O0[QbO<<I`OOQ`,5:P,5:POOQ`-E7c-E7cOOQ`AN>mAN>mO'PQbO'#D]OOQ`'#Dh'#DhO0gQbOAN>zO0rQQO'#D_OOQ`AN>zAN>zO0wQbOAN>zO0|QRO,59wO1TQQO,59wOOQ`-E7f-E7fOOQ`G24fG24fO1YQbOG24fO1_QQO,59yO1dQQO1G/cOOQ`LD*QLD*QO.lQbO1G/eO/YQbO7+$}OOQ`7+%P7+%POOQ`<<Hi<<Hi",
stateData: "1l~O!_OS!`OS~O]PO^_O_WO`XOjSOrWOsWOtWOuWO|]O!gUO!jbO!mVO~O]eO_WO`XOjSOrWOsWOtWOuWOwfOygO!gUO!mVOzfX!jfX!wfX!lfXmfX~OP!eXQ!eXR!eXS!eXT!eXU!eXV!eXW!eXX!eXY!eXZ!eX[!eX~P!TOPkOQkORlOSlO~OPkOQkORlOSlO!j!bX!w!bXm!bX~O^mOlkP~O]PO_WO`XOjSOrWOsWOtWOuWO!gUO!mVO~OowO!mzO!ouO!pvO~O!t{O~OP!eXQ!eXR!eXS!eX!j!bX!w!bXm!bX~Oz|O!j!bX!w!bXm!bX~O]eO_WO`XOrWOsWOtWOuWO!gUO!mVO~OV!QO~O!j!RO!w!RO~OjSOw!TO~P'POjSOwfOygOzca!jca!wca!lcamca~P'PO^mOlkX~Ol!YO~OT![OU![OV!ZOW!ZOX!ZOY!ZOZ!ZO[!ZO~OPkOQkORlOSlO~P)QOPkOQkORlOSlO!l!]O~O!l!]OP!eXQ!eXR!eXS!eXT!eXU!eXV!eXW!eXX!eXY!eXZ!eX[!eX~Oz|O!l!]O~O]!^O!gUO~O!m!_O!o!_O!p!_O!q!_O!r!_O!s!_O~OowO!m!aO!ouO!pvO~O]!bO~O]!cO~Oz|O!jba!wba!lbamba~Ol!fO~P)QOl!fO~O^_O|]O~P%TOPkOQkORgiSgi!jgi!wgi!lgimgi~O^_O|]O!j!iO~P%TO^_O|]O!j!nO~P%TOm!oO~O^_O|]Om!kP~P%TO!lhilhi~P)QOm!sO~O^_O|]Om!kP!Q!kP!S!kP~P%TO!j!vO~O^_O|]Om!kX!Q!kX!S!kX~P%TOm!xO~Om!}O!Q!yO!S!|O~Om#SO!Q!yO!S!|O~Ol#UO~Om#SO~Ol#VO~P)QOl#VO~Om#WO~O!j#XO~O!j#YO~Ort~",
goto: "+r!wPPPPPPPPPPPPPPPPPP!x#X#g#l#X$W$m$yP%bPP%eP%|%|PPPP&QP#gPP&kP&w&z'TP'XP&k'_'e'l'r'{(R(YPPPP(`(d(x)[)a*[P*w*wP+YPP+bPPPPPP+f+fd`Od!Q!Y!f!i!n!q#X#YRsUiZOUd|!Q!Y!f!i!n!q#X#YVhPj!czWOPU]dgjkl!Q!Y!Z![!c!f!i!n!q!y#X#YR!^udROd!Q!Y!f!i!n!q#X#YQqUQ!VkR!WlQsUQ!P]Q!j![R#Q!yd`Od!Q!Y!f!i!n!q#X#YUfPj!cQsUR!TgRoS{WOPU]dgjkl!Q!Y!Z![!c!f!i!n!q!y#X#YTwVydYOd!Q!Y!f!i!n!q#X#YgePU]gjkl!Z![!c!ye`Od!Q!Y!f!i!n!q#X#YR!m!fQ!u!nQ#Z#XR#[#YT!z!u!{Q#O!uR#T!{QdOR!SdSjP!cR!UjQnSR!XnW!q!i!n#X#YR!w!qQyVR!`yS}[tR!e}Q!{!uR#R!{TcOdSaOdQ!g!QQ!h!YQ!l!fZ!p!i!n!q#X#Yd[Od!Q!Y!f!i!n!q#X#YQtUR!d|ViPj!cdQOd!Q!Y!f!i!n!q#X#YUfPj!cQpUQ!O]Q!TgQ!VkQ!WlQ!j!ZQ!k![R#P!ydYOd!Q!Y!f!i!n!q#X#YdeP]gjkl!Z![!c!yRrUoTOPUdgj!Q!Y!c!f!i!n!q#X#YQ!r!iV!t!n#X#YTxVye^Od!Q!Y!f!i!n!q#X#Y",
nodeNames: "⚠ Star Slash Plus Minus And Or Eq Neq Lt Lte Gt Gte Identifier AssignableIdentifier Word IdentifierBeforeDot Program PipeExpr FunctionCall PositionalArg ParenExpr FunctionCallOrIdentifier BinOp ConditionalOp FunctionDef keyword Params colon keyword String StringFragment Interpolation EscapeSeq Number Boolean Regex Null DotGet Underscore NamedArg NamedArgPrefix operator IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword Assign",
maxTerm: 85,
context: trackScope,
nodeProps: [
@ -23,5 +23,5 @@ export const parser = LRParser.deserialize({
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!t~~", 11)],
topRules: {"Program":[0,17]},
specialized: [{term: 13, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
tokenPrec: 756
tokenPrec: 761
})

View File

@ -4,7 +4,7 @@ import '../shrimp.grammar' // Importing this so changes cause it to retest!
describe('if/elseif/else', () => {
test('parses single line if', () => {
expect(`if y = 1: 'cool'`).toMatchTree(`
expect(`if y = 1: 'cool' end`).toMatchTree(`
IfExpr
keyword if
ConditionalOp
@ -12,12 +12,13 @@ describe('if/elseif/else', () => {
Eq =
Number 1
colon :
ThenBlock
SingleLineThenBlock
String
StringFragment cool
keyword end
`)
expect('a = if x: 2').toMatchTree(`
expect('a = if x: 2 end').toMatchTree(`
Assign
AssignableIdentifier a
Eq =
@ -25,8 +26,9 @@ describe('if/elseif/else', () => {
keyword if
Identifier x
colon :
ThenBlock
SingleLineThenBlock
Number 2
keyword end
`)
})
@ -138,7 +140,7 @@ describe('if/elseif/else', () => {
})
test('does not parse identifiers that start with if', () => {
expect('iffy = if true: 2').toMatchTree(`
expect('iffy = if true: 2 end').toMatchTree(`
Assign
AssignableIdentifier iffy
Eq =
@ -146,8 +148,9 @@ describe('if/elseif/else', () => {
keyword if
Boolean true
colon :
ThenBlock
SingleLineThenBlock
Number 2
keyword end
`)
})
})