basic emitter in place
This commit is contained in:
parent
9986e96309
commit
3405c10b08
14
src/nds.nim
14
src/nds.nim
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue