Added switch statements
This commit is contained in:
parent
af3c7234be
commit
f1875736e3
|
@ -851,6 +851,8 @@ proc dispatch*(self: var PeonVM) =
|
||||||
# Pops N elements off the call stack
|
# Pops N elements off the call stack
|
||||||
for _ in 0..<int(self.readShort()):
|
for _ in 0..<int(self.readShort()):
|
||||||
discard self.popc()
|
discard self.popc()
|
||||||
|
of DupTop:
|
||||||
|
self.push(self.peek())
|
||||||
# Jump opcodes
|
# Jump opcodes
|
||||||
of Jump:
|
of Jump:
|
||||||
# Absolute jump
|
# Absolute jump
|
||||||
|
|
|
@ -2629,6 +2629,26 @@ proc namedBlock(self: Compiler, node: NamedBlockStmt) =
|
||||||
self.endScope()
|
self.endScope()
|
||||||
|
|
||||||
|
|
||||||
|
proc switchStmt(self: Compiler, node: SwitchStmt) =
|
||||||
|
## Compiles switch statements
|
||||||
|
self.expression(node.switch)
|
||||||
|
var ifJump: int = -1
|
||||||
|
var thenJumps: seq[int] = @[]
|
||||||
|
for branch in node.branches:
|
||||||
|
self.emitByte(DupTop, branch.body.token.line)
|
||||||
|
self.expression(branch.cond)
|
||||||
|
self.emitByte(Equal, branch.body.token.line)
|
||||||
|
ifJump = self.emitJump(JumpIfFalsePop, branch.body.token.line)
|
||||||
|
self.blockStmt(branch.body)
|
||||||
|
thenJumps.add(self.emitJump(JumpForwards, branch.body.token.line))
|
||||||
|
self.patchJump(ifJump)
|
||||||
|
if not node.default.isNil():
|
||||||
|
self.blockStmt(node.default)
|
||||||
|
for jump in thenJumps:
|
||||||
|
self.patchJump(jump)
|
||||||
|
self.emitByte(OpCode.Pop, node.token.line)
|
||||||
|
|
||||||
|
|
||||||
proc statement(self: Compiler, node: Statement) =
|
proc statement(self: Compiler, node: Statement) =
|
||||||
## Compiles all statements
|
## Compiles all statements
|
||||||
case node.kind:
|
case node.kind:
|
||||||
|
@ -2644,6 +2664,8 @@ proc statement(self: Compiler, node: Statement) =
|
||||||
self.printRepl(kind, expression)
|
self.printRepl(kind, expression)
|
||||||
else:
|
else:
|
||||||
self.emitByte(Pop, node.token.line)
|
self.emitByte(Pop, node.token.line)
|
||||||
|
of NodeKind.switchStmt:
|
||||||
|
self.switchStmt(SwitchStmt(node))
|
||||||
of NodeKind.namedBlockStmt:
|
of NodeKind.namedBlockStmt:
|
||||||
self.namedBlocks.add(NamedBlock(start: self.chunk.code.len(),
|
self.namedBlocks.add(NamedBlock(start: self.chunk.code.len(),
|
||||||
depth: self.depth,
|
depth: self.depth,
|
||||||
|
|
|
@ -77,7 +77,8 @@ type
|
||||||
identExpr, # Identifier
|
identExpr, # Identifier
|
||||||
pragmaExpr,
|
pragmaExpr,
|
||||||
refExpr,
|
refExpr,
|
||||||
ptrExpr
|
ptrExpr,
|
||||||
|
switchStmt
|
||||||
|
|
||||||
# Here I would've rather used object variants, and in fact that's what was in
|
# Here I would've rather used object variants, and in fact that's what was in
|
||||||
# place before, but not being able to re-declare a field of the same type in
|
# place before, but not being able to re-declare a field of the same type in
|
||||||
|
@ -291,6 +292,11 @@ type
|
||||||
|
|
||||||
Ptr* = ref object of Expression
|
Ptr* = ref object of Expression
|
||||||
value*: Expression
|
value*: Expression
|
||||||
|
|
||||||
|
SwitchStmt* = ref object of Statement
|
||||||
|
switch*: Expression
|
||||||
|
branches*: seq[tuple[cond: Expression, body: BlockStmt]]
|
||||||
|
default*: BlockStmt
|
||||||
|
|
||||||
|
|
||||||
proc isConst*(self: ASTNode): bool =
|
proc isConst*(self: ASTNode): bool =
|
||||||
|
@ -337,6 +343,15 @@ proc newPtrExpr*(expression: Expression, token: Token): Ptr =
|
||||||
result.token = token
|
result.token = token
|
||||||
|
|
||||||
|
|
||||||
|
proc newSwitchStmt*(switch: Expression, branches: seq[tuple[cond: Expression, body: BlockStmt]], default: BlockStmt, token: Token): SwitchStmt =
|
||||||
|
new(result)
|
||||||
|
result.kind = switchStmt
|
||||||
|
result.switch = switch
|
||||||
|
result.branches = branches
|
||||||
|
result.token = token
|
||||||
|
result.default = default
|
||||||
|
|
||||||
|
|
||||||
proc newIntExpr*(literal: Token): IntExpr =
|
proc newIntExpr*(literal: Token): IntExpr =
|
||||||
result = IntExpr(kind: intExpr)
|
result = IntExpr(kind: intExpr)
|
||||||
result.literal = literal
|
result.literal = literal
|
||||||
|
|
|
@ -186,7 +186,8 @@ type
|
||||||
PopC, # Pop off the call stack onto the operand stack
|
PopC, # Pop off the call stack onto the operand stack
|
||||||
PushC, # Pop off the operand stack onto the call stack
|
PushC, # Pop off the operand stack onto the call stack
|
||||||
SysClock64, # Pushes the output of a monotonic clock on the stack
|
SysClock64, # Pushes the output of a monotonic clock on the stack
|
||||||
LoadTOS # Pushes the top of the call stack onto the operand stack
|
LoadTOS, # Pushes the top of the call stack onto the operand stack
|
||||||
|
DupTop # Duplicates the top of the operand stack onto the operand stack
|
||||||
|
|
||||||
|
|
||||||
# We group instructions by their operation/operand types for easier handling when debugging
|
# We group instructions by their operation/operand types for easier handling when debugging
|
||||||
|
@ -265,6 +266,7 @@ const simpleInstructions* = {Return, LoadNil,
|
||||||
Float32LessThan,
|
Float32LessThan,
|
||||||
Float32GreaterOrEqual,
|
Float32GreaterOrEqual,
|
||||||
Float32LessOrEqual,
|
Float32LessOrEqual,
|
||||||
|
DupTop
|
||||||
}
|
}
|
||||||
|
|
||||||
# Constant instructions are instructions that operate on the bytecode constant table
|
# Constant instructions are instructions that operate on the bytecode constant table
|
||||||
|
|
|
@ -38,7 +38,7 @@ type
|
||||||
Yield, Defer, Try, Except,
|
Yield, Defer, Try, Except,
|
||||||
Finally, Type, Operator, Case,
|
Finally, Type, Operator, Case,
|
||||||
Enum, From, Ptr, Ref, Object,
|
Enum, From, Ptr, Ref, Object,
|
||||||
Export, Block, Template
|
Export, Block, Template, Switch,
|
||||||
|
|
||||||
# Literal types
|
# Literal types
|
||||||
Integer, Float, String, Identifier,
|
Integer, Float, String, Identifier,
|
||||||
|
|
|
@ -1203,12 +1203,37 @@ proc expressionStatement(self: Parser): Statement =
|
||||||
result.file = self.file
|
result.file = self.file
|
||||||
|
|
||||||
|
|
||||||
|
proc switchStmt(self: Parser): Statement =
|
||||||
|
## Parses switch statements
|
||||||
|
let tok = self.peek(-1)
|
||||||
|
let switch = self.expression()
|
||||||
|
self.expect(TokenType.LeftBrace, "expecting '{' after switch condition")
|
||||||
|
var branches: seq[tuple[cond: Expression, body: BlockStmt]] = @[]
|
||||||
|
var match: Expression
|
||||||
|
var body: BlockStmt
|
||||||
|
var default: BlockStmt
|
||||||
|
while not self.check([TokenType.RightBrace, TokenType.Else]) and not self.done():
|
||||||
|
self.expect(TokenType.Case, "expecting at least one 'case' label in switch statement")
|
||||||
|
match = self.expression()
|
||||||
|
self.expect(TokenType.LeftBrace, "expecting '{' after expression match in switch statement")
|
||||||
|
body = BlockStmt(self.blockStmt())
|
||||||
|
branches.add((cond: match, body: body))
|
||||||
|
if self.match(Else):
|
||||||
|
self.expect(TokenType.LeftBrace, "expecting '{' after else clause in switch statement")
|
||||||
|
default = BlockStmt(self.blockStmt())
|
||||||
|
self.expect(TokenType.RightBrace, "missing closing '}' in switch statement")
|
||||||
|
result = newSwitchStmt(switch, branches, default, tok)
|
||||||
|
|
||||||
|
|
||||||
proc statement(self: Parser): Statement =
|
proc statement(self: Parser): Statement =
|
||||||
## Parses statements
|
## Parses statements
|
||||||
case self.peek().kind:
|
case self.peek().kind:
|
||||||
of If:
|
of If:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.ifStmt()
|
result = self.ifStmt()
|
||||||
|
of Switch:
|
||||||
|
discard self.step()
|
||||||
|
result = self.switchStmt()
|
||||||
of Assert:
|
of Assert:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.assertStmt()
|
result = self.assertStmt()
|
||||||
|
|
|
@ -46,6 +46,9 @@ proc fillSymbolTable*(tokenizer: Lexer) =
|
||||||
tokenizer.symbols.addKeyword("return", TokenType.Return)
|
tokenizer.symbols.addKeyword("return", TokenType.Return)
|
||||||
tokenizer.symbols.addKeyword("object", Object)
|
tokenizer.symbols.addKeyword("object", Object)
|
||||||
tokenizer.symbols.addKeyword("export", Export)
|
tokenizer.symbols.addKeyword("export", Export)
|
||||||
|
tokenizer.symbols.addKeyword("block", TokenType.Block)
|
||||||
|
tokenizer.symbols.addKeyword("template", TokenType.Template)
|
||||||
|
tokenizer.symbols.addKeyword("switch", TokenType.Switch)
|
||||||
# These are more like expressions with a reserved
|
# These are more like expressions with a reserved
|
||||||
# name that produce a value of a builtin type,
|
# name that produce a value of a builtin type,
|
||||||
# but we don't need to care about that until
|
# but we don't need to care about that until
|
||||||
|
@ -55,8 +58,6 @@ proc fillSymbolTable*(tokenizer: Lexer) =
|
||||||
tokenizer.symbols.addKeyword("false", False)
|
tokenizer.symbols.addKeyword("false", False)
|
||||||
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
|
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
|
||||||
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
|
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
|
||||||
tokenizer.symbols.addKeyword("block", TokenType.Block)
|
|
||||||
tokenizer.symbols.addKeyword("template", TokenType.Template)
|
|
||||||
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":", "==", "!=",
|
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":", "==", "!=",
|
||||||
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%", "&", "|", "^",
|
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%", "&", "|", "^",
|
||||||
">>", "<<"]:
|
">>", "<<"]:
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import std;
|
||||||
|
|
||||||
|
|
||||||
|
switch 2 + 2 {
|
||||||
|
case 4 {
|
||||||
|
print(true);
|
||||||
|
}
|
||||||
|
case 3 {
|
||||||
|
print(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch 2 + 1 {
|
||||||
|
case 4 {
|
||||||
|
print(false);
|
||||||
|
}
|
||||||
|
case 3 {
|
||||||
|
print(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch 2 + 3 {
|
||||||
|
case 4 {
|
||||||
|
print(false);
|
||||||
|
}
|
||||||
|
case 3 {
|
||||||
|
print(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print(true);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue