Compare commits
3 Commits
0c6ce16bcd
...
2175bf2dd7
| Author | SHA1 | Date | |
|---|---|---|---|
| 2175bf2dd7 | |||
| 36e8a88aae | |||
| 6ca64d362c |
|
|
@ -334,17 +334,15 @@ export class Compiler {
|
||||||
if (opValue === '??=') {
|
if (opValue === '??=') {
|
||||||
instructions.push(['LOAD', identifierName])
|
instructions.push(['LOAD', identifierName])
|
||||||
|
|
||||||
const skipLabel: Label = `.skip_${this.labelCount++}`
|
|
||||||
const rightInstructions = this.#compileNode(right, input)
|
const rightInstructions = this.#compileNode(right, input)
|
||||||
|
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
instructions.push(['PUSH', null])
|
instructions.push(['PUSH', null])
|
||||||
instructions.push(['NEQ'])
|
instructions.push(['NEQ'])
|
||||||
instructions.push(['JUMP_IF_TRUE', skipLabel])
|
instructions.push(['JUMP_IF_TRUE', rightInstructions.length + 1])
|
||||||
instructions.push(['POP'])
|
instructions.push(['POP'])
|
||||||
instructions.push(...rightInstructions)
|
instructions.push(...rightInstructions)
|
||||||
|
|
||||||
instructions.push([`${skipLabel}:`])
|
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
instructions.push(['STORE', identifierName])
|
instructions.push(['STORE', identifierName])
|
||||||
|
|
||||||
|
|
@ -442,8 +440,8 @@ export class Compiler {
|
||||||
case terms.FunctionCallOrIdentifier: {
|
case terms.FunctionCallOrIdentifier: {
|
||||||
if (node.firstChild?.type.id === terms.DotGet) {
|
if (node.firstChild?.type.id === terms.DotGet) {
|
||||||
const instructions: ProgramItem[] = []
|
const instructions: ProgramItem[] = []
|
||||||
const callLabel: Label = `.call_dotget_${++this.labelCount}`
|
const callLabel = `.call_dotget_${++this.labelCount}`
|
||||||
const afterLabel: Label = `.after_dotget_${++this.labelCount}`
|
const afterLabel = `.after_dotget_${++this.labelCount}`
|
||||||
|
|
||||||
instructions.push(...this.#compileNode(node.firstChild, input))
|
instructions.push(...this.#compileNode(node.firstChild, input))
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
|
|
@ -605,24 +603,19 @@ export class Compiler {
|
||||||
instructions.push(...this.#compileNode(conditionNode, input))
|
instructions.push(...this.#compileNode(conditionNode, input))
|
||||||
this.ifLabelCount++
|
this.ifLabelCount++
|
||||||
const endLabel: Label = `.end_${this.ifLabelCount}`
|
const endLabel: Label = `.end_${this.ifLabelCount}`
|
||||||
const elseLabel: Label = `.else_${this.ifLabelCount}`
|
|
||||||
|
|
||||||
const thenBlockInstructions = this.#compileNode(thenBlock, input)
|
const thenBlockInstructions = this.#compileNode(thenBlock, input)
|
||||||
instructions.push(['JUMP_IF_FALSE', elseLabel])
|
instructions.push(['JUMP_IF_FALSE', thenBlockInstructions.length + 1])
|
||||||
instructions.push(...thenBlockInstructions)
|
instructions.push(...thenBlockInstructions)
|
||||||
instructions.push(['JUMP', endLabel])
|
instructions.push(['JUMP', endLabel])
|
||||||
|
|
||||||
instructions.push([`${elseLabel}:`])
|
|
||||||
|
|
||||||
// Else if
|
// Else if
|
||||||
elseIfBlocks.forEach(({ conditional, thenBlock }, index) => {
|
elseIfBlocks.forEach(({ conditional, thenBlock }) => {
|
||||||
instructions.push(...this.#compileNode(conditional, input))
|
instructions.push(...this.#compileNode(conditional, input))
|
||||||
const nextLabel: Label = `.elsif_${this.ifLabelCount}_${index}`
|
|
||||||
const elseIfInstructions = this.#compileNode(thenBlock, input)
|
const elseIfInstructions = this.#compileNode(thenBlock, input)
|
||||||
instructions.push(['JUMP_IF_FALSE', nextLabel])
|
instructions.push(['JUMP_IF_FALSE', elseIfInstructions.length + 1])
|
||||||
instructions.push(...elseIfInstructions)
|
instructions.push(...elseIfInstructions)
|
||||||
instructions.push(['JUMP', endLabel])
|
instructions.push(['JUMP', endLabel])
|
||||||
instructions.push([`${nextLabel}:`])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Else
|
// Else
|
||||||
|
|
@ -671,41 +664,34 @@ export class Compiler {
|
||||||
instructions.push(...leftInstructions, ...rightInstructions, ['GTE'])
|
instructions.push(...leftInstructions, ...rightInstructions, ['GTE'])
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'and': {
|
case 'and':
|
||||||
const skipLabel: Label = `.skip_${this.labelCount++}`
|
|
||||||
instructions.push(...leftInstructions)
|
instructions.push(...leftInstructions)
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
instructions.push(['JUMP_IF_FALSE', skipLabel])
|
instructions.push(['JUMP_IF_FALSE', rightInstructions.length + 1])
|
||||||
instructions.push(['POP'])
|
instructions.push(['POP'])
|
||||||
instructions.push(...rightInstructions)
|
instructions.push(...rightInstructions)
|
||||||
instructions.push([`${skipLabel}:`])
|
|
||||||
break
|
break
|
||||||
}
|
|
||||||
|
|
||||||
case 'or': {
|
case 'or':
|
||||||
const skipLabel: Label = `.skip_${this.labelCount++}`
|
|
||||||
instructions.push(...leftInstructions)
|
instructions.push(...leftInstructions)
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
instructions.push(['JUMP_IF_TRUE', skipLabel])
|
instructions.push(['JUMP_IF_TRUE', rightInstructions.length + 1])
|
||||||
instructions.push(['POP'])
|
instructions.push(['POP'])
|
||||||
instructions.push(...rightInstructions)
|
instructions.push(...rightInstructions)
|
||||||
instructions.push([`${skipLabel}:`])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
case '??': {
|
break
|
||||||
|
|
||||||
|
case '??':
|
||||||
// Nullish coalescing: return left if not null, else right
|
// Nullish coalescing: return left if not null, else right
|
||||||
const skipLabel: Label = `.skip_${this.labelCount++}`
|
|
||||||
instructions.push(...leftInstructions)
|
instructions.push(...leftInstructions)
|
||||||
instructions.push(['DUP'])
|
instructions.push(['DUP'])
|
||||||
instructions.push(['PUSH', null])
|
instructions.push(['PUSH', null])
|
||||||
instructions.push(['NEQ'])
|
instructions.push(['NEQ'])
|
||||||
instructions.push(['JUMP_IF_TRUE', skipLabel])
|
instructions.push(['JUMP_IF_TRUE', rightInstructions.length + 1])
|
||||||
instructions.push(['POP'])
|
instructions.push(['POP'])
|
||||||
instructions.push(...rightInstructions)
|
instructions.push(...rightInstructions)
|
||||||
instructions.push([`${skipLabel}:`])
|
|
||||||
break
|
break
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new CompilerError(`Unsupported conditional operator: ${opValue}`, op.from, op.to)
|
throw new CompilerError(`Unsupported conditional operator: ${opValue}`, op.from, op.to)
|
||||||
|
|
|
||||||
|
|
@ -188,16 +188,6 @@ describe('compiler', () => {
|
||||||
test('single line if', () => {
|
test('single line if', () => {
|
||||||
expect(`if 3 < 9: shire end`).toEvaluateTo('shire')
|
expect(`if 3 < 9: shire end`).toEvaluateTo('shire')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('if statement with function definition (bytecode labels)', () => {
|
|
||||||
expect(`
|
|
||||||
if false:
|
|
||||||
abc = do x: x end
|
|
||||||
else:
|
|
||||||
nope
|
|
||||||
end
|
|
||||||
`).toEvaluateTo('nope')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('errors', () => {
|
describe('errors', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user