basic emitter in place

This commit is contained in:
prod2 2022-12-03 11:52:51 +01:00
parent 9986e96309
commit 3405c10b08
6 changed files with 244 additions and 51 deletions

View File

@ -1,12 +1,14 @@
import ndspkg/vm import ndspkg/vm
import ndspkg/compv2/parser import ndspkg/compv2/parser
import ndspkg/compv2/node import ndspkg/compv2/node
import ndspkg/compv2/emitter
import ndspkg/config import ndspkg/config
when compilerChoice == cmOne: when compilerChoice == cmOne:
import ndspkg/compiler/compiler import ndspkg/compiler/compiler
import ndspkg/compiler/types import ndspkg/compiler/types
import os import os
import strformat import strformat
@ -18,6 +20,18 @@ proc interpret(name: string, source: string): Result =
let parser = newParser(name, source) let parser = newParser(name, source)
let node = parser.parse() let node = parser.parse()
echo $node echo $node
elif compilerChoice == cmTwo:
let parser = newParser(name, source)
let node = parser.parse()
if parser.hadError:
return rsCompileError
let emitter = newEmitter(name, node)
emitter.emit()
case emitter.chunk.run():
of irOK:
rsOK
of irRuntimeError:
rsRuntimeError
elif compilerChoice == cmOne: elif compilerChoice == cmOne:
let compiler = newCompiler(name, source) let compiler = newCompiler(name, source)
compiler.compile() compiler.compile()

View File

@ -0,0 +1,166 @@
# a new bytecode emitter for nds
# emitter: takes AST, emits bytecode. It also binds variables.
import node
import ../chunk
import ../config
import ../types/value
import strformat
type
Emitter* = ref object
root: Node
chunk*: Chunk
hadError*: bool
line: int
# binding
stackIndex: int
locals: seq[Local]
scopes: seq[Scope]
Local = ref object
name: string
index: int # index in the stack (0 - stack bottom)
depth: int # depth of the local
# -1 if cannot be referenced yet
scope: Scope # innermost scope
captured: bool
Upvalue* = ref object
index: int
isLocal: bool
Scope = ref object
labels: seq[string]
goalStackIndex: int # stack count it started with plus 1
jumps: seq[int] # list of jumps to be patched to the end of the scope
function: bool # if true, it's a function
parentFunction: Scope # if function, itself. Else, the innermost function it's in
upvalues: seq[Upvalue] # for functions, list of upvalues
# helpers
proc newEmitter*(name: string, root: Node): Emitter =
new(result)
result.root = root
result.chunk = initChunk(name)
result.stackIndex = -1
proc error(em: Emitter, msg: string) =
write stderr, &"[line {em.line}] Error {msg}\n"
em.hadError = true
proc newScope(em: Emitter, funct: bool): Scope =
result.new()
result.function = funct
result.goalStackIndex = em.stackIndex + 1
if funct:
result.parentFunction = result
elif em.scopes.len() > 0:
result.parentFunction = em.scopes[em.scopes.high()].parentFunction
em.scopes.add(result)
# chunk writers
proc writeChunk(em: Emitter, dStackIndex: int, ch: OpCode | DoubleUint8 | uint8) =
em.stackIndex += dStackIndex
em.chunk.writeChunk(ch, em.line)
proc writePops(em: Emitter, n: int) =
if n == 0:
return
elif n > argMax:
em.error("Too many local variables in block.")
elif n == 1:
em.writeChunk(-1, opPop)
elif n < shortArgMax:
em.writeChunk(-n, opPopSA)
em.writeChunk(0, n.uint8)
else:
em.writeChunk(-n, opPopA)
em.writeChunk(0, n.toDU8())
proc writeConstant(em: Emitter, constant: NdValue) =
em.stackIndex.inc()
let index = em.chunk.writeConstant(constant, em.line)
if index >= argMax:
em.error("Too many constants in one chunk.")
# locals helpers
proc addLocal(em: Emitter, name: string, delta: int) =
if em.locals.len >= argMax:
em.error("Too many local variables in function.")
# TODO: check if it can be increased
# if delta is 0 or negative - means that the var is already on stack when addLocal is called
# if delta is +, the first ever value of the local is about to be added
# so it should be -1, (see Local typedef) to indicate that it cannot be referenced yet
let depth = if delta > 0: -1 else: em.scopes.high
em.locals.add(
Local(name: name, depth: depth, index: em.stackIndex + delta, scope: em.scopes[em.scopes.high()], captured: false)
)
proc markInitialized(em: Emitter) =
em.locals[em.locals.high()].depth = em.scopes.high()
# node compilers
proc emit(em: Emitter, node: Node) =
em.line = node.line
case node.kind:
of nkFalse:
em.writeChunk(1, opFalse)
of nkTrue:
em.writeChunk(1, opTrue)
of nkNil:
em.writeChunk(1, opNil)
of nkConst:
em.writeConstant(node.constant)
of nkNegate:
em.emit(node.argument)
em.writeChunk(0, opNegate)
of nkNot:
em.emit(node.argument)
em.writeChunk(0, opNot)
of nkLen:
em.emit(node.argument)
em.writeChunk(0, opLen)
of nkBlockExpr:
# TODO: scopes
for ch in node.children:
em.emit(ch)
of nkExpr:
em.emit(node.expression)
of nkExprStmt:
em.emit(node.expression)
em.writePops(1)
of nkPlus, nkMinus, nkMult, nkDiv, nkEq, nkNeq, nkGreater, nkLess, nkGe, nkLe:
em.emit(node.left)
em.emit(node.right)
case node.kind:
of nkPlus: em.writeChunk(-1, opAdd)
of nkMinus: em.writeChunk(-1, opSubtract)
of nkMult: em.writeChunk(-1, opMultiply)
of nkDiv: em.writeChunk(-1, opDivide)
of nkEq: em.writeChunk(-1, opEqual)
of nkNeq:
em.writeChunk(-1, opEqual)
em.writeChunk(0, opNot)
of nkGreater:
em.writeChunk(-1, opGreater)
of nkLess:
em.writeChunk(-1, opLess)
of nkGe:
em.writeChunk(-1, opLess)
em.writeChunk(0, opNot)
of nkLe:
em.writeChunk(-1, opGreater)
em.writeChunk(0, opNot)
else:
raise newException(Defect, "Misaligned case list.") # unreachable
else:
raise newException(Defect, &"Unsupported node kind: {$node.kind}")
proc emit*(em: Emitter) =
em.emit(em.root)
em.writeChunk(0, opReturn) # required for the vm to exit gracefully

View File

@ -12,9 +12,11 @@ type
nkPlus, nkMinus, nkMult, nkDiv, nkEq, nkNeq, nkLess, nkGreater, nkPlus, nkMinus, nkMult, nkDiv, nkEq, nkNeq, nkLess, nkGreater,
nkGe, nkLe, nkGe, nkLe,
nkCall, nkColonCall, nkVarDecl, nkProc, nkCall, nkColonCall, nkVarDecl, nkProc,
nkVarGet, nkVarSet nkVarGet, nkVarSet,
nkFalse, nkTrue, nkNil
Node* = ref object Node* = ref object
line*: int
case kind*: NodeKind: case kind*: NodeKind:
of nkBlockExpr: of nkBlockExpr:
children*: seq[Node] children*: seq[Node]
@ -63,6 +65,8 @@ type
of nkVarSet: of nkVarSet:
sVarName*: string sVarName*: string
newVal*: Node newVal*: Node
of nkFalse, nkTrue, nkNil:
discard
proc `$`*(node: Node): string = proc `$`*(node: Node): string =
if node == nil: if node == nil:
@ -98,6 +102,8 @@ proc `$`*(node: Node): string =
result = &"(grouping {node.expression})" result = &"(grouping {node.expression})"
of nkExprStmt: of nkExprStmt:
result = &"(exprStmt {node.expression})" result = &"(exprStmt {node.expression})"
of nkFalse:
result = "(false)"
of nkGe: of nkGe:
result = &"(ge {node.left} {node.right})" result = &"(ge {node.left} {node.right})"
of nkGetIndex: of nkGetIndex:
@ -125,6 +131,8 @@ proc `$`*(node: Node): string =
result = &"(neg {node.argument})" result = &"(neg {node.argument})"
of nkNeq: of nkNeq:
result = &"(!= {node.left} {node.right})" result = &"(!= {node.left} {node.right})"
of nkNil:
result = "(nil)"
of nkNot: of nkNot:
result = &"(! {node.argument})" result = &"(! {node.argument})"
of nkOr: of nkOr:
@ -143,6 +151,8 @@ proc `$`*(node: Node): string =
keys &= &"{node.keys[i]}, " keys &= &"{node.keys[i]}, "
values &= &"{node.values[i]}, " values &= &"{node.values[i]}, "
result = &"(table keys: {keys}, values: {values})" result = &"(table keys: {keys}, values: {values})"
of nkTrue:
result = "(true)"
of nkVarDecl: of nkVarDecl:
result = &"(varDecl {node.name} = {node.value})" result = &"(varDecl {node.name} = {node.value})"
of nkVarGet: of nkVarGet:

View File

@ -21,6 +21,7 @@ type
current: Token current: Token
previous: Option[Token] previous: Option[Token]
next: Option[Token] next: Option[Token]
line: int
# if there is a next set, advance won't trigger the scanner # if there is a next set, advance won't trigger the scanner
# it will use next instead # it will use next instead
hold: Node # temporary hold, used to implement ampersand op hold: Node # temporary hold, used to implement ampersand op
@ -59,6 +60,7 @@ proc errorAtCurrent(parser: Parser, msg: string) =
proc advance(parser: Parser) = proc advance(parser: Parser) =
parser.previous = some(parser.current) parser.previous = some(parser.current)
parser.line = parser.current.line
while true: while true:
if parser.next.isSome(): if parser.next.isSome():
parser.current = parser.next.get() parser.current = parser.next.get()
@ -129,7 +131,7 @@ proc statement(parser: Parser, inBlock: bool = false): Node
proc exprNonAssign(parser: Parser): Node proc exprNonAssign(parser: Parser): Node
proc parseList(parser: Parser): Node = proc parseList(parser: Parser): Node =
result = Node(kind: nkList, elems: @[]) result = Node(kind: nkList, elems: @[], line: parser.line)
while not parser.isAtEnd() and not parser.peekMatch(tkRightBracket): while not parser.isAtEnd() and not parser.peekMatch(tkRightBracket):
result.elems.add(parser.expression()) result.elems.add(parser.expression())
@ -139,7 +141,7 @@ proc parseList(parser: Parser): Node =
discard parser.consume(tkRightBracket, "']' expected after list declaration.") discard parser.consume(tkRightBracket, "']' expected after list declaration.")
proc parseTable(parser: Parser): Node = proc parseTable(parser: Parser): Node =
result = Node(kind: nkTable, keys: @[], values: @[]) result = Node(kind: nkTable, keys: @[], values: @[], line: parser.line)
while not parser.isAtEnd() and not parser.peekMatch(tkRightBrace): while not parser.isAtEnd() and not parser.peekMatch(tkRightBrace):
# [key] = syntax # [key] = syntax
@ -148,7 +150,7 @@ proc parseTable(parser: Parser): Node =
discard parser.consume(tkRightBracket, "']' expected after table key.") discard parser.consume(tkRightBracket, "']' expected after table key.")
# key = syntax # key = syntax
elif parser.match(tkIdentifier): elif parser.match(tkIdentifier):
result.keys.add(Node(kind: nkConst, constant: parser.previous.get().text.fromNimString())) result.keys.add(Node(kind: nkConst, constant: parser.previous.get().text.fromNimString(), line: parser.line))
else: else:
parser.errorAtCurrent("Key expected (have you forgotten to put the key in brackets?).") parser.errorAtCurrent("Key expected (have you forgotten to put the key in brackets?).")
discard parser.consume(tkEqual, "'=' expected after key.") discard parser.consume(tkEqual, "'=' expected after key.")
@ -176,10 +178,10 @@ proc parseProcDeclaration(parser: Parser): Node =
let body = parser.expression() let body = parser.expression()
result = Node(kind: nkProc, parameters: params, procBody: body) result = Node(kind: nkProc, parameters: params, procBody: body, line: parser.line)
proc parseBlock(parser: Parser): Node = proc parseBlock(parser: Parser): Node =
result = Node(kind: nkBlockExpr, children: @[], labels: @[]) result = Node(kind: nkBlockExpr, children: @[], labels: @[], line: parser.line)
while parser.match(tkLabel): while parser.match(tkLabel):
result.labels.add(parser.previous.get().text[1..^1]) result.labels.add(parser.previous.get().text[1..^1])
@ -201,19 +203,19 @@ proc parseBlock(parser: Parser): Node =
proc primary(parser: Parser): Node = proc primary(parser: Parser): Node =
if parser.match(tkFalse): if parser.match(tkFalse):
return Node(kind: nkConst, constant: ndFalse) return Node(kind: nkFalse, line: parser.line)
if parser.match(tkTrue): if parser.match(tkTrue):
return Node(kind: nkConst, constant: ndTrue) return Node(kind: nkTrue, line: parser.line)
if parser.match(tkNil): if parser.match(tkNil):
return Node(kind: nkConst, constant: ndNil) return Node(kind: nkNil, line: parser.line)
if parser.match(tkNumber): if parser.match(tkNumber):
return Node(kind: nkConst, constant: fromFloat(parseFloat(parser.previous.get().text))) return Node(kind: nkConst, constant: fromFloat(parseFloat(parser.previous.get().text)), line: parser.line)
if parser.match(tkString): if parser.match(tkString):
return Node(kind: nkConst, constant: fromNimString(parser.previous.get().text[1..^2])) return Node(kind: nkConst, constant: fromNimString(parser.previous.get().text[1..^2]), line: parser.line)
if parser.match(tkLeftParen): if parser.match(tkLeftParen):
let grouped = parser.expression() let grouped = parser.expression()
discard parser.consume(tkRightParen, "Expect ')' after expression.") discard parser.consume(tkRightParen, "Expect ')' after expression.")
return Node(kind: nkExpr, expression: grouped) return Node(kind: nkExpr, expression: grouped, line: parser.line)
if parser.match(tkLeftBrace): if parser.match(tkLeftBrace):
return parser.parseBlock() return parser.parseBlock()
if parser.match(tkStartList): if parser.match(tkStartList):
@ -221,7 +223,7 @@ proc primary(parser: Parser): Node =
if parser.match(tkStartTable): if parser.match(tkStartTable):
return parser.parseTable() return parser.parseTable()
if parser.match(tkIdentifier): if parser.match(tkIdentifier):
return Node(kind: nkVarGet, gVarName: parser.previous.get().text) return Node(kind: nkVarGet, gVarName: parser.previous.get().text, line: parser.line)
if parser.match(tkAmpersand): if parser.match(tkAmpersand):
result = parser.hold result = parser.hold
parser.hold = nil parser.hold = nil
@ -253,31 +255,31 @@ proc parseIndex(parser: Parser): Node =
let index = parser.expression() let index = parser.expression()
if not parser.consume(tkRightBracket, "']' after index."): if not parser.consume(tkRightBracket, "']' after index."):
break break
result = Node(kind: nkGetIndex, gCollection: result, gIndex: index) result = Node(kind: nkGetIndex, gCollection: result, gIndex: index, line: parser.line)
elif parser.previous.get().tokenType == tkIdentifier: elif parser.previous.get().tokenType == tkIdentifier:
let identText = parser.previous.get().text let identText = parser.previous.get().text
if identText[0] != ':': if identText[0] != ':':
parser.errorAtCurrent("';' expected after expression statement.") parser.errorAtCurrent("';' expected after expression statement.")
# update this with whatever the original error when two idents follow eachother is # update this with whatever the original error when two idents follow eachother is
return return
let ident = Node(kind: nkConst, constant: identText[1..^1].fromNimString()) let ident = Node(kind: nkConst, constant: identText[1..^1].fromNimString(), line: parser.line)
# ident removes the : from it # ident removes the : from it
var args: seq[Node] = @[] var args: seq[Node] = @[]
if parser.match(tkLeftParen): if parser.match(tkLeftParen):
args = parser.parseArgList() args = parser.parseArgList()
let funct = Node(kind: nkGetIndex, gCollection: result, gIndex: ident) let funct = Node(kind: nkGetIndex, gCollection: result, gIndex: ident, line: parser.line)
result = Node(kind: nkColonCall, arguments: args, function: funct) result = Node(kind: nkColonCall, arguments: args, function: funct, line: parser.line)
else: else:
# dot # dot
if not parser.consume(tkIdentifier, "Identifier expected after '.' index operator."): if not parser.consume(tkIdentifier, "Identifier expected after '.' index operator."):
break break
result = Node(kind: nkGetIndex, gCollection: result, gIndex: Node(kind: nkConst, constant: parser.previous.get().text.fromNimString())) result = Node(kind: nkGetIndex, gCollection: result, gIndex: Node(kind: nkConst, constant: parser.previous.get().text.fromNimString()), line: parser.line)
proc parseCall(parser: Parser): Node = proc parseCall(parser: Parser): Node =
result = parser.parseIndex() result = parser.parseIndex()
if parser.match(tkLeftParen): if parser.match(tkLeftParen):
let args = parser.parseArgList() let args = parser.parseArgList()
result = Node(kind: nkCall, arguments: args, function: result) result = Node(kind: nkCall, arguments: args, function: result, line: parser.line)
proc parseIf(parser: Parser): Node = proc parseIf(parser: Parser): Node =
@ -286,7 +288,7 @@ proc parseIf(parser: Parser): Node =
discard parser.consume(tkRightParen, "')' expected after condition.") discard parser.consume(tkRightParen, "')' expected after condition.")
let body = parser.expression() let body = parser.expression()
result = Node(kind: nkIf, ifCondition: cond, ifBody: body) result = Node(kind: nkIf, ifCondition: cond, ifBody: body, line: parser.line)
if parser.match(tkElse): if parser.match(tkElse):
result.elseBody = parser.expression() result.elseBody = parser.expression()
@ -296,7 +298,7 @@ proc parseWhile(parser:Parser): Node =
discard parser.consume(tkRightParen, "')' expected after condition.") discard parser.consume(tkRightParen, "')' expected after condition.")
let body = parser.expression() let body = parser.expression()
result = Node(kind: nkWhile, whileCondition: cond, whileBody: body) result = Node(kind: nkWhile, whileCondition: cond, whileBody: body, line: parser.line)
proc unary(parser: Parser): Node = proc unary(parser: Parser): Node =
# unary level for unary operators, plus some control flow is here too # unary level for unary operators, plus some control flow is here too
@ -306,13 +308,13 @@ proc unary(parser: Parser): Node =
case op.tokenType: case op.tokenType:
of tkBang: of tkBang:
let right = parser.unary() let right = parser.unary()
return Node(kind: nkNot, argument: right) return Node(kind: nkNot, argument: right, line: parser.line)
of tkMinus: of tkMinus:
let right = parser.unary() let right = parser.unary()
return Node(kind: nkNegate, argument: right) return Node(kind: nkNegate, argument: right, line: parser.line)
of tkHashtag: of tkHashtag:
let right = parser.unary() let right = parser.unary()
return Node(kind: nkLen, argument: right) return Node(kind: nkLen, argument: right, line: parser.line)
of tkIf: of tkIf:
return parser.parseIf() return parser.parseIf()
of tkWhile: of tkWhile:
@ -328,9 +330,9 @@ proc factor(parser: Parser): Node =
let op = parser.previous.get() let op = parser.previous.get()
let right = parser.unary() let right = parser.unary()
if op.tokenType == tkSlash: if op.tokenType == tkSlash:
result = Node(kind: nkDiv, left: result, right: right) result = Node(kind: nkDiv, left: result, right: right, line: parser.line)
else: else:
result = Node(kind: nkMult, left: result, right: right) result = Node(kind: nkMult, left: result, right: right, line: parser.line)
proc term(parser: Parser): Node = proc term(parser: Parser): Node =
result = parser.factor() result = parser.factor()
@ -339,9 +341,9 @@ proc term(parser: Parser): Node =
let op = parser.previous.get() let op = parser.previous.get()
let right = parser.factor() let right = parser.factor()
if op.tokenType == tkMinus: if op.tokenType == tkMinus:
result = Node(kind: nkMinus, left: result, right: right) result = Node(kind: nkMinus, left: result, right: right, line: parser.line)
else: else:
result = Node(kind: nkPlus, left: result, right: right) result = Node(kind: nkPlus, left: result, right: right, line: parser.line)
proc comparison(parser: Parser): Node = proc comparison(parser: Parser): Node =
result = parser.term() result = parser.term()
@ -351,13 +353,13 @@ proc comparison(parser: Parser): Node =
let right = parser.term() let right = parser.term()
case op.tokenType: case op.tokenType:
of tkGreater: of tkGreater:
result = Node(kind: nkGreater, left: result, right: right) result = Node(kind: nkGreater, left: result, right: right, line: parser.line)
of tkGreaterEqual: of tkGreaterEqual:
result = Node(kind: nkGe, left: result, right: right) result = Node(kind: nkGe, left: result, right: right, line: parser.line)
of tkLess: of tkLess:
result = Node(kind: nkLess, left: result, right: right) result = Node(kind: nkLess, left: result, right: right, line: parser.line)
of tkLessEqual: of tkLessEqual:
result = Node(kind: nkLe, left: result, right: right) result = Node(kind: nkLe, left: result, right: right, line: parser.line)
else: else:
parser.errorAtCurrent("invalid state in comparison: case and set don't match up.") parser.errorAtCurrent("invalid state in comparison: case and set don't match up.")
@ -368,9 +370,9 @@ proc equality(parser: Parser): Node =
let op = parser.previous.get() let op = parser.previous.get()
let right = parser.comparison() let right = parser.comparison()
if op.tokenType == tkBangEqual: if op.tokenType == tkBangEqual:
result = Node(kind: nkNeq, left: result, right: right) result = Node(kind: nkNeq, left: result, right: right, line: parser.line)
else: else:
result = Node(kind: nkEq, left: result, right: right) result = Node(kind: nkEq, left: result, right: right, line: parser.line)
proc parseAnd(parser: Parser): Node = proc parseAnd(parser: Parser): Node =
@ -378,14 +380,14 @@ proc parseAnd(parser: Parser): Node =
while parser.match(tkAnd): while parser.match(tkAnd):
let right = parser.equality() let right = parser.equality()
result = Node(kind: nkAnd, left: result, right: right) result = Node(kind: nkAnd, left: result, right: right, line: parser.line)
proc parseOr(parser: Parser): Node = proc parseOr(parser: Parser): Node =
result = parser.parseAnd() result = parser.parseAnd()
while parser.match(tkOr): while parser.match(tkOr):
let right = parser.parseAnd() let right = parser.parseAnd()
result = Node(kind: nkOr, left: result, right: right) result = Node(kind: nkOr, left: result, right: right, line: parser.line)
proc parsePipeCall(parser: Parser): Node = proc parsePipeCall(parser: Parser): Node =
result = parser.parseOr() result = parser.parseOr()
@ -403,7 +405,7 @@ proc parsePipeCall(parser: Parser): Node =
result = right result = right
# else: right val is a function which we call # else: right val is a function which we call
else: else:
result = Node(kind: nkCall, arguments: @[result], function: right) result = Node(kind: nkCall, arguments: @[result], function: right, line: parser.line)
proc exprNonAssign(parser: Parser): Node = proc exprNonAssign(parser: Parser): Node =
@ -421,15 +423,15 @@ proc parseAssign(parser: Parser): Node =
parser.errorAtCurrent("Attempt to assign to invalid target.") parser.errorAtCurrent("Attempt to assign to invalid target.")
return return
if result.kind == nkVarGet: if result.kind == nkVarGet:
result = Node(kind: nkVarSet, sVarName: result.gVarName, newVal: right) result = Node(kind: nkVarSet, sVarName: result.gVarName, newVal: right, line: parser.line)
else: else:
# nkGetIndex # nkGetIndex
result = Node(kind: nkSetIndex, sCollection: result.gCollection, sIndex: result.gIndex, sValue: right) result = Node(kind: nkSetIndex, sCollection: result.gCollection, sIndex: result.gIndex, sValue: right, line: parser.line)
proc parseAmpersand(parser: Parser): Node = proc parseAmpersand(parser: Parser): Node =
result = parser.parseAssign() result = parser.parseAssign()
if parser.match(tkAmpersand): if parser.match(tkAmpersand):
parser.hold = Node(kind: nkExpr, expression: result) parser.hold = Node(kind: nkExpr, expression: result, line: parser.line)
parser.backtrack() parser.backtrack()
return parser.parseAmpersand() return parser.parseAmpersand()
@ -440,11 +442,11 @@ proc expression(parser: Parser): Node =
proc exprStatement(parser: Parser, inBlock: bool): Node = proc exprStatement(parser: Parser, inBlock: bool): Node =
let expression = parser.expression() let expression = parser.expression()
if expression != nil: if expression != nil:
result = Node(kind: nkExprStmt, expression: expression) result = Node(kind: nkExprStmt, expression: expression, line: parser.line)
else: else:
parser.errorAtCurrent("Expression expected.") parser.errorAtCurrent("Expression expected.")
if parser.peekMatch(tkRightBrace) and inBlock: if parser.peekMatch(tkRightBrace) and inBlock:
result = Node(kind: nkExpr, expression: result.expression) # block should also check if it is the last expr. result = Node(kind: nkExpr, expression: result.expression, line: parser.line) # block should also check if it is the last expr.
else: else:
discard parser.consume(tkSemicolon, "';' expected after expression statement.") discard parser.consume(tkSemicolon, "';' expected after expression statement.")
@ -463,22 +465,22 @@ proc statement(parser: Parser, inBlock: bool = false): Node =
let varname = parser.previous.get().text let varname = parser.previous.get().text
discard parser.consume(tkLeftParen, "'(' expected after procedure name.") discard parser.consume(tkLeftParen, "'(' expected after procedure name.")
let funct = parser.parseProcDeclaration() let funct = parser.parseProcDeclaration()
result = Node(kind: nkVarDecl, name: varname, value: funct) result = Node(kind: nkVarDecl, name: varname, value: funct, line: parser.line)
discard parser.consume(tkSemicolon, "';' expected after procedure declaration.") discard parser.consume(tkSemicolon, "';' expected after procedure declaration.")
elif parser.match(tkBreak): elif parser.match(tkBreak):
if parser.match(tkLabel): if parser.match(tkLabel):
result = Node(kind: nkBreak, label: parser.previous.get().text[1..^1]) result = Node(kind: nkBreak, label: parser.previous.get().text[1..^1], line: parser.line)
else: else:
result = Node(kind: nkBreak, label: "") result = Node(kind: nkBreak, label: "", line: parser.line)
discard parser.consume(tkSemicolon, "';' expected after break statement.") discard parser.consume(tkSemicolon, "';' expected after break statement.")
elif parser.match(tkVar): elif parser.match(tkVar):
discard parser.consume(tkIdentifier, "Identifier expected after 'var'.") discard parser.consume(tkIdentifier, "Identifier expected after 'var'.")
let name = parser.previous.get().text let name = parser.previous.get().text
if parser.match(tkEqual): if parser.match(tkEqual):
let val = parser.expression() let val = parser.expression()
result = Node(kind: nkVarDecl, name: name, value: val) result = Node(kind: nkVarDecl, name: name, value: val, line: parser.line)
else: else:
result = Node(kind: nkVarDecl, name: name, value: nil) result = Node(kind: nkVarDecl, name: name, value: nil, line: parser.line)
discard parser.consume(tkSemicolon, "';' expected after variable declaration.") discard parser.consume(tkSemicolon, "';' expected after variable declaration.")
else: else:
result = parser.exprStatement(inBlock) result = parser.exprStatement(inBlock)
@ -488,7 +490,7 @@ proc statement(parser: Parser, inBlock: bool = false): Node =
proc parse*(parser: Parser): Node = proc parse*(parser: Parser): Node =
parser.scanner = newScanner(parser.source) parser.scanner = newScanner(parser.source)
result = Node(kind: nkBlockExpr, children: @[]) result = Node(kind: nkBlockExpr, children: @[], line: parser.line)
parser.advance() parser.advance()
while not parser.isAtEnd(): while not parser.isAtEnd():

View File

@ -16,11 +16,12 @@ const profileInstructions* = defined(ndsprofile) # if true, the time spent on ev
const debugClosures* = defined(debug) # specific closure debug switches const debugClosures* = defined(debug) # specific closure debug switches
type compMode* = enum type compMode* = enum
cmOne, cmAst cmOne, cmAst, cmTwo
const compilerChoice* = cmAst const compilerChoice* = cmTwo
# choose a compiler: cmOne - version 1, deprecated # choose a compiler: cmOne - version 1, deprecated
# cmAst - version 2, but only use parser and print AST produced # cmAst - version 2, but only use parser and print AST produced
# cmOne will be removed once compv2 is done # cmOne will be removed once compv2 is done
# cmTwo - compv2 + execute
# choose a line editor for the repl # choose a line editor for the repl
const lineEditor = leRdstdin const lineEditor = leRdstdin

View File

@ -164,7 +164,7 @@ proc run*(chunk: Chunk): InterpretResult =
setForegroundColor(fgYellow) setForegroundColor(fgYellow)
disassembleInstruction(chunk, ii, ll) disassembleInstruction(chunk, ii, ll)
setForegroundColor(fgDefault) setForegroundColor(fgDefault)
write stdout, " " echo ""
when profileInstructions: when profileInstructions:
let startTime = getMonoTime() let startTime = getMonoTime()