derete the fil #2
|
@ -267,10 +267,11 @@ proc patchJump(self: Compiler, offset: int) =
|
|||
## offset and changes the bytecode instruction if possible
|
||||
## (i.e. jump is in 16 bit range), but the converse is also
|
||||
## true (i.e. it might change a regular jump into a long one)
|
||||
let jump: int = self.chunk.code.len() - offset
|
||||
var jump: int = self.chunk.code.len() - offset
|
||||
if jump > 16777215:
|
||||
self.error("cannot jump more than 16777216 bytecode instructions")
|
||||
if jump < uint16.high().int:
|
||||
jump -= 3
|
||||
case OpCode(self.chunk.code[offset]):
|
||||
of LongJumpForwards:
|
||||
self.chunk.code[offset] = JumpForwards.uint8()
|
||||
|
@ -289,6 +290,7 @@ proc patchJump(self: Compiler, offset: int) =
|
|||
self.chunk.code[offset + 1] = offsetArray[0]
|
||||
self.chunk.code[offset + 2] = offsetArray[1]
|
||||
else:
|
||||
jump -= 4
|
||||
case OpCode(self.chunk.code[offset]):
|
||||
of JumpForwards:
|
||||
self.chunk.code[offset] = LongJumpForwards.uint8()
|
||||
|
@ -457,6 +459,8 @@ proc toIntrinsic(name: string): Type =
|
|||
|
||||
proc inferType(self: Compiler, node: LiteralExpr): Type =
|
||||
## Infers the type of a given literal expression
|
||||
if node == nil:
|
||||
return nil
|
||||
case node.kind:
|
||||
of intExpr, binExpr, octExpr, hexExpr:
|
||||
let size = node.token.lexeme.split("'")
|
||||
|
@ -514,6 +518,8 @@ proc toIntrinsic(self: Compiler, typ: Expression): Type =
|
|||
proc inferType(self: Compiler, node: Expression): Type =
|
||||
## Infers the type of a given expression and
|
||||
## returns it
|
||||
if node == nil:
|
||||
return nil
|
||||
case node.kind:
|
||||
of identExpr:
|
||||
let node = IdentExpr(node)
|
||||
|
@ -576,6 +582,8 @@ proc typeToStr(self: Compiler, typ: Type): string =
|
|||
proc inferType(self: Compiler, node: Declaration): Type =
|
||||
## Infers the type of a given declaration
|
||||
## and returns it
|
||||
if node == nil:
|
||||
return nil
|
||||
case node.kind:
|
||||
of funDecl:
|
||||
var node = FunDecl(node)
|
||||
|
@ -1043,14 +1051,18 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
|
|||
## implicitly returns nil
|
||||
let returnType = self.inferType(node.value)
|
||||
let typ = self.inferType(self.currentFunction)
|
||||
if returnType == nil and self.currentFunction.returnType != nil:
|
||||
self.error(&"expected return value of type '{self.currentFunction.returnType.token.lexeme}', but expression has no type")
|
||||
elif self.currentFunction.returnType == nil and node.value.kind != nilExpr:
|
||||
self.error("non-nil return value is not allowed in functions without an explicit return type")
|
||||
## Having the return type
|
||||
if typ.returnType == nil and returnType != nil:
|
||||
self.error("non-empty return statement is not allowed in functions without an explicit return type")
|
||||
elif returnType == nil and typ.returnType != nil:
|
||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', but expression has no type")
|
||||
elif not self.compareTypes(returnType, typ.returnType):
|
||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', got '{self.typeToStr(returnType)}' instead")
|
||||
self.expression(node.value)
|
||||
self.emitByte(OpCode.Return)
|
||||
if node.value != nil:
|
||||
self.expression(node.value)
|
||||
self.emitByte(OpCode.ReturnPop)
|
||||
else:
|
||||
self.emitByte(OpCode.Return)
|
||||
|
||||
|
||||
proc yieldStmt(self: Compiler, node: YieldStmt) =
|
||||
|
@ -1171,6 +1183,8 @@ proc funDecl(self: Compiler, node: FunDecl) =
|
|||
## Compiles function declarations
|
||||
self.declareName(node)
|
||||
if node.body != nil:
|
||||
if BlockStmt(node.body).code.len() == 0:
|
||||
self.error("Cannot declare function with empty body")
|
||||
let fnType = self.inferType(node)
|
||||
let impl = self.findByType(node.name.token.lexeme, fnType)
|
||||
if impl.len() > 1:
|
||||
|
@ -1178,9 +1192,9 @@ proc funDecl(self: Compiler, node: FunDecl) =
|
|||
# the same function! Error!
|
||||
var msg = &"multiple matching implementations of '{node.name.token.lexeme}' found:\n"
|
||||
for fn in reversed(impl):
|
||||
var node = Declaration(fn.valueType.node)
|
||||
var node = FunDecl(fn.valueType.node)
|
||||
discard self.typeToStr(fn.valueType)
|
||||
msg &= &"- '{node.name.lexeme}' at line {node.token.line} of type {self.typeToStr(fn.valueType)}\n"
|
||||
msg &= &"- '{node.name.token.lexeme}' at line {node.token.line} of type {self.typeToStr(fn.valueType)}\n"
|
||||
self.error(msg)
|
||||
# We store the current function
|
||||
var function = self.currentFunction
|
||||
|
|
|
@ -96,7 +96,7 @@ type
|
|||
# work properly
|
||||
Declaration* = ref object of ASTNode
|
||||
## A declaration
|
||||
pragmas*: seq[Token]
|
||||
pragmas*: seq[Pragma]
|
||||
Statement* = ref object of Declaration
|
||||
## A statement
|
||||
Expression* = ref object of Statement
|
||||
|
@ -252,6 +252,9 @@ type
|
|||
isPrivate*: bool
|
||||
isPure*: bool
|
||||
returnType*: Expression
|
||||
Pragma* = ref object of Expression
|
||||
name*: IdentExpr
|
||||
args*: seq[LiteralExpr]
|
||||
|
||||
|
||||
proc isConst*(self: ASTNode): bool =
|
||||
|
@ -524,7 +527,7 @@ proc newIfStmt*(condition: Expression, thenBranch, elseBranch: Statement,
|
|||
|
||||
proc newVarDecl*(name: IdentExpr, value: Expression, isConst: bool = false,
|
||||
isPrivate: bool = true, token: Token, isLet: bool = false,
|
||||
valueType: Expression, pragmas: seq[Token]): VarDecl =
|
||||
valueType: Expression, pragmas: seq[Pragma]): VarDecl =
|
||||
result = VarDecl(kind: varDecl)
|
||||
result.name = name
|
||||
result.value = value
|
||||
|
@ -538,7 +541,7 @@ proc newVarDecl*(name: IdentExpr, value: Expression, isConst: bool = false,
|
|||
|
||||
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression, mutable: bool, isRef: bool, isPtr: bool]], defaults: seq[Expression],
|
||||
body: Statement, isAsync, isGenerator: bool,
|
||||
isPrivate: bool, token: Token, pragmas: seq[Token],
|
||||
isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
||||
returnType: Expression): FunDecl =
|
||||
result = FunDecl(kind: funDecl)
|
||||
result.name = name
|
||||
|
|
|
@ -111,8 +111,9 @@ type
|
|||
LongJumpForwards,
|
||||
LongJumpBackwards,
|
||||
## Functions
|
||||
Call, # Calls a function
|
||||
Return # Returns from the current function
|
||||
Call, # Calls a function and initiates a new stack frame
|
||||
Return, # Terminates the current function without popping off the stack
|
||||
ReturnPop, # Pops a return value off the stack and terminates the current function
|
||||
## Exception handling
|
||||
Raise, # Raises exception x or re-raises active exception if x is nil
|
||||
BeginTry, # Initiates an exception handling context
|
||||
|
@ -135,7 +136,8 @@ const simpleInstructions* = {OpCode.Return, LoadNil,
|
|||
Pop, OpCode.Raise,
|
||||
BeginTry, FinishTry,
|
||||
OpCode.Yield, OpCode.Await,
|
||||
OpCode.NoOp}
|
||||
OpCode.NoOp, OpCode.Return,
|
||||
OpCode.ReturnPop}
|
||||
|
||||
# Constant instructions are instructions that operate on the bytecode constant table
|
||||
const constantInstructions* = {LoadInt64, LoadUInt64,
|
||||
|
|
|
@ -568,10 +568,9 @@ proc returnStmt(self: Parser): Statement =
|
|||
let tok = self.peek(-1)
|
||||
if self.currentFunction == nil:
|
||||
self.error("'return' cannot be used outside functions")
|
||||
var value: Expression = newNilExpr(Token(lexeme: "nil"))
|
||||
var value: Expression
|
||||
if not self.check(Semicolon):
|
||||
# Since return can be used on its own too
|
||||
# (in which case it implicitly returns nil),
|
||||
# we need to check if there's an actual value
|
||||
# to return or not
|
||||
value = self.expression()
|
||||
|
|
25
src/test.nim
25
src/test.nim
|
@ -25,9 +25,9 @@ proc getLineEditor: LineEditor
|
|||
# Handy dandy compile-time constants
|
||||
const debugLexer = false
|
||||
const debugParser = false
|
||||
const debugCompiler = false
|
||||
const debugCompiler = true
|
||||
const debugSerializer = false
|
||||
|
||||
const debugRuntime = false
|
||||
|
||||
when debugSerializer:
|
||||
import nimSHA2
|
||||
|
@ -119,30 +119,31 @@ when isMainModule:
|
|||
if i < len(serialized.chunk.code) - 1:
|
||||
stdout.write(", ")
|
||||
stdout.write(&"] (matches: {serialized.chunk.code == compiled.code})\n")
|
||||
echo "Execution step: "
|
||||
when debugRuntime:
|
||||
echo "Execution step: "
|
||||
vm.run(serialized.chunk)
|
||||
except IOError:
|
||||
break
|
||||
# TODO: The code for error reporting completely
|
||||
# breaks down with multiline input, fix it
|
||||
except LexingError:
|
||||
let lineNo = tokenizer.getLine()
|
||||
let relPos = tokenizer.getRelPos(lineNo)
|
||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
# let lineNo = tokenizer.getLine()
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||
except ParseError:
|
||||
let lineNo = parser.getCurrentToken().line
|
||||
let relPos = tokenizer.getRelPos(lineNo)
|
||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
# let lineNo = parser.getCurrentToken().line
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - parser.getCurrentToken().lexeme.len())
|
||||
except CompileError:
|
||||
let lineNo = compiler.getCurrentNode().token.line
|
||||
let relPos = tokenizer.getRelPos(lineNo)
|
||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
# let lineNo = compiler.getCurrentNode().token.line
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - compiler.getCurrentNode().token.lexeme.len())
|
||||
|
|
Loading…
Reference in New Issue