Fixed issues with negative numbers and infinity. Variables can now accept function expressions as type arguments. Compiler.infer() now always returns a concrete type, minor bug fix in varDecl
This commit is contained in:
parent
8667cbdceb
commit
c7893fb14b
|
@ -695,6 +695,8 @@ proc dispatch*(self: PeonVM) =
|
|||
self.push(self.getNil())
|
||||
of LoadInf:
|
||||
self.push(self.getInf(true))
|
||||
of LoadNInf:
|
||||
self.push(self.getInf(false))
|
||||
of LoadInt64:
|
||||
self.push(uint64(self.constReadInt64(int(self.readLong()))))
|
||||
of LoadUInt64:
|
||||
|
@ -907,7 +909,7 @@ proc dispatch*(self: PeonVM) =
|
|||
# types, we don't need specialized instructions
|
||||
# to operate on them
|
||||
of Negate:
|
||||
self.push(uint64(-int64(self.pop())))
|
||||
self.push(cast[uint64](-int64(self.pop())))
|
||||
of NegateFloat64:
|
||||
self.push(cast[uint64](-cast[float](self.pop())))
|
||||
of NegateFloat32:
|
||||
|
@ -979,19 +981,19 @@ proc dispatch*(self: PeonVM) =
|
|||
self.push(self.getBool(self.pop() <= self.pop()))
|
||||
# Print opcodes
|
||||
of PrintInt64:
|
||||
echo int64(self.pop())
|
||||
echo cast[int64](self.pop())
|
||||
of PrintUInt64:
|
||||
echo self.pop()
|
||||
of PrintInt32:
|
||||
echo int32(self.pop())
|
||||
echo cast[int32](self.pop())
|
||||
of PrintUInt32:
|
||||
echo uint32(self.pop())
|
||||
of PrintInt16:
|
||||
echo int16(self.pop())
|
||||
echo cast[int16](self.pop())
|
||||
of PrintUInt16:
|
||||
echo uint16(self.pop())
|
||||
of PrintInt8:
|
||||
echo int8(self.pop())
|
||||
echo cast[int8](self.pop())
|
||||
of PrintUInt8:
|
||||
echo uint8(self.pop())
|
||||
of PrintFloat32:
|
||||
|
@ -1007,9 +1009,9 @@ proc dispatch*(self: PeonVM) =
|
|||
echo "false"
|
||||
of PrintInf:
|
||||
if self.pop() == 0x3:
|
||||
echo "-inf"
|
||||
else:
|
||||
echo "inf"
|
||||
else:
|
||||
echo "-inf"
|
||||
of PrintNan:
|
||||
echo "nan"
|
||||
of PrintString:
|
||||
|
|
|
@ -219,6 +219,7 @@ proc declaration(self: Compiler, node: Declaration)
|
|||
proc peek(self: Compiler, distance: int = 0): ASTNode
|
||||
proc identifier(self: Compiler, node: IdentExpr)
|
||||
proc varDecl(self: Compiler, node: VarDecl, name: Name)
|
||||
proc specializeGeneric(self: Compiler, fn: Name, args: seq[Expression]): Name
|
||||
proc matchImpl(self: Compiler, name: string, kind: Type, node: ASTNode = nil): Name
|
||||
proc infer(self: Compiler, node: LiteralExpr): Type
|
||||
proc infer(self: Compiler, node: Expression): Type
|
||||
|
@ -754,7 +755,7 @@ proc infer(self: Compiler, node: LiteralExpr): Type =
|
|||
proc infer(self: Compiler, node: Expression): Type =
|
||||
## Infers the type of a given expression and
|
||||
## returns it (if the node is nil, nil is
|
||||
## returned)
|
||||
## returned). Always returns a concrete type
|
||||
if node.isNil():
|
||||
return nil
|
||||
case node.kind:
|
||||
|
@ -767,24 +768,30 @@ proc infer(self: Compiler, node: Expression): Type =
|
|||
if name.belongsTo.isNil():
|
||||
name = self.resolve(result.name)
|
||||
if not name.isNil():
|
||||
return name.valueType
|
||||
result = name.valueType
|
||||
else:
|
||||
for arg in name.belongsTo.valueType.args:
|
||||
if node.token.lexeme == arg.name:
|
||||
return arg.kind
|
||||
result = arg.kind
|
||||
else:
|
||||
result = node.name.lexeme.toIntrinsic()
|
||||
of unaryExpr:
|
||||
let node = UnaryExpr(node)
|
||||
return self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(node.a))]), node).valueType.returnType
|
||||
let impl = self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(node.a))]), node)
|
||||
result = impl.valueType.returnType
|
||||
if result.kind == Generic:
|
||||
result = self.specializeGeneric(impl, @[node.a]).valueType.returnType
|
||||
of binaryExpr:
|
||||
let node = BinaryExpr(node)
|
||||
return self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(node.a)), ("", self.infer(node.b))]), node).valueType.returnType
|
||||
let impl = self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(node.a)), ("", self.infer(node.b))]), node)
|
||||
result = impl.valueType.returnType
|
||||
if result.kind == Generic:
|
||||
result = self.specializeGeneric(impl, @[node.a, node.b]).valueType.returnType
|
||||
of {intExpr, hexExpr, binExpr, octExpr,
|
||||
strExpr, falseExpr, trueExpr, infExpr,
|
||||
nanExpr, floatExpr, nilExpr
|
||||
}:
|
||||
return self.infer(LiteralExpr(node))
|
||||
result = self.infer(LiteralExpr(node))
|
||||
of lambdaExpr:
|
||||
var node = LambdaExpr(node)
|
||||
result = Type(kind: Function, returnType: nil, args: @[], isLambda: true)
|
||||
|
@ -820,6 +827,7 @@ proc infer(self: Compiler, node: Expression): Type =
|
|||
result = self.infer(GroupingExpr(node).expression)
|
||||
else:
|
||||
discard # Unreachable
|
||||
|
||||
|
||||
|
||||
proc typeToStr(self: Compiler, typ: Type): string =
|
||||
|
@ -1004,7 +1012,8 @@ proc handleBuiltinFunction(self: Compiler, fn: Type, args: seq[Expression], line
|
|||
"PrintInf": PrintInf,
|
||||
"PrintString": PrintString,
|
||||
"SysClock64": SysClock64,
|
||||
"LogicalNot": LogicalNot
|
||||
"LogicalNot": LogicalNot,
|
||||
"NegInf": LoadNInf
|
||||
}.to_table()
|
||||
if fn.builtinOp in codes:
|
||||
self.emitByte(codes[fn.builtinOp], line)
|
||||
|
@ -1915,8 +1924,6 @@ proc printRepl(self: Compiler, typ: Type, node: Expression) =
|
|||
## Emits instruction to print
|
||||
## peon types in REPL mode
|
||||
case typ.kind:
|
||||
of Generic:
|
||||
discard # TODO
|
||||
of Int64:
|
||||
self.emitByte(PrintInt64, node.token.line)
|
||||
of UInt64:
|
||||
|
@ -2010,25 +2017,21 @@ proc varDecl(self: Compiler, node: VarDecl, name: Name) =
|
|||
if expected.isNil() and actual.isNil():
|
||||
if node.value.kind == identExpr or node.value.kind == callExpr and CallExpr(node.value).callee.kind == identExpr:
|
||||
var name = node.value.token.lexeme
|
||||
if node.value.kind == callExpr:
|
||||
if node.value.kind == callExpr and CallExpr(node.value).callee.kind == identExpr:
|
||||
name = CallExpr(node.value).callee.token.lexeme
|
||||
if self.resolve(name).isNil():
|
||||
self.error(&"reference to undeclared name '{name}'")
|
||||
self.error(&"'{node.name.token.lexeme}' has no type")
|
||||
elif not expected.isNil() and expected.mutable: # I mean, variables *are* already mutable (some of them anyway)
|
||||
if not expected.isNil() and expected.mutable: # I mean, variables *are* already mutable (some of them anyway)
|
||||
self.error(&"invalid type '{self.typeToStr(expected)}' for var")
|
||||
elif not self.compare(expected, actual):
|
||||
if not expected.isNil():
|
||||
self.error(&"expected value of type '{self.typeToStr(expected)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(actual)}'")
|
||||
if expected.isNil():
|
||||
name.valueType = actual
|
||||
if actual.kind == Generic:
|
||||
# We matched a generic type, but we
|
||||
# need the concrete one
|
||||
name.valueType = expected
|
||||
self.expression(node.value)
|
||||
self.emitByte(StoreVar, node.token.line)
|
||||
self.emitBytes(self.getStackPos(self.names[^1]).toTriple(), node.token.line)
|
||||
self.emitBytes(self.getStackPos(name).toTriple(), node.token.line)
|
||||
|
||||
|
||||
proc typeDecl(self: Compiler, node: TypeDecl, name: Name) =
|
||||
|
|
|
@ -84,6 +84,7 @@ type
|
|||
LoadFalse,
|
||||
LoadNan,
|
||||
LoadInf,
|
||||
LoadNInf,
|
||||
## Operations on primitive types
|
||||
Negate,
|
||||
NegateFloat64,
|
||||
|
@ -184,7 +185,7 @@ type
|
|||
const simpleInstructions* = {Return, LoadNil,
|
||||
LoadTrue, LoadFalse,
|
||||
LoadNan, LoadInf,
|
||||
Pop, Raise,
|
||||
Pop, Raise, LoadNInf,
|
||||
BeginTry, FinishTry, Yield,
|
||||
Await, NoOp, SetResult,
|
||||
PopC, PushC, SysClock64,
|
||||
|
|
|
@ -297,6 +297,7 @@ proc expressionStatement(self: Parser): Statement
|
|||
proc statement(self: Parser): Statement
|
||||
proc varDecl(self: Parser, isLet: bool = false,
|
||||
isConst: bool = false): Declaration
|
||||
proc parseFunExpr(self: Parser): LambdaExpr
|
||||
proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||
isLambda: bool = false, isOperator: bool = false): Declaration
|
||||
proc declaration(self: Parser): Declaration
|
||||
|
@ -890,13 +891,14 @@ proc varDecl(self: Parser, isLet: bool = false,
|
|||
valueType = newIdentExpr(self.peek(-1), self.scopeDepth)
|
||||
if self.match("="):
|
||||
hasInit = true
|
||||
value = self.expression()
|
||||
if self.match([Function, Coroutine, Generator]):
|
||||
value = self.parseFunExpr()
|
||||
else:
|
||||
value = self.expression()
|
||||
if isConst and not value.isConst():
|
||||
self.error("constant initializer is not a constant")
|
||||
else:
|
||||
if tok.kind != TokenType.Var:
|
||||
self.error(&"{tok.lexeme} declaration requires an initializer")
|
||||
value = newNilExpr(Token(lexeme: "nil"))
|
||||
elif tok.kind != TokenType.Var:
|
||||
self.error(&"{tok.lexeme} declaration requires an initializer")
|
||||
self.expect(Semicolon, "expecting semicolon after declaration")
|
||||
if self.match(TokenType.Pragma):
|
||||
for pragma in self.parsePragmas():
|
||||
|
|
|
@ -147,8 +147,6 @@ proc repl =
|
|||
except LexingError:
|
||||
input = ""
|
||||
var exc = LexingError(getCurrentException())
|
||||
if exc.lexeme == "":
|
||||
exc.line -= 1
|
||||
let relPos = exc.lexer.getRelPos(exc.line)
|
||||
let line = exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'})
|
||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ",
|
||||
|
@ -157,12 +155,11 @@ proc repl =
|
|||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||
except ParseError:
|
||||
echo getCurrentExceptionMsg()
|
||||
input = ""
|
||||
let exc = ParseError(getCurrentException())
|
||||
let lexeme = exc.token.lexeme
|
||||
var lineNo = exc.token.line
|
||||
if exc.token.kind == EndOfFile:
|
||||
lineNo -= 1
|
||||
let relPos = exc.parser.getRelPos(lineNo)
|
||||
let fn = parser.getCurrentFunction()
|
||||
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||
|
@ -178,8 +175,6 @@ proc repl =
|
|||
let exc = CompileError(getCurrentException())
|
||||
let lexeme = exc.node.token.lexeme
|
||||
var lineNo = exc.node.token.line
|
||||
if exc.node.token.kind == EndOfFile:
|
||||
lineNo -= 1
|
||||
let relPos = exc.compiler.getRelPos(lineNo)
|
||||
let line = exc.compiler.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||
var fn = exc.compiler.getCurrentFunction()
|
||||
|
|
20
tests/std.pn
20
tests/std.pn
|
@ -38,6 +38,26 @@ operator `-`*(a, b: float32): float32 {
|
|||
}
|
||||
|
||||
|
||||
operator `-`*[T: int | int32 | int16 | int8](a: T): T {
|
||||
#pragma[magic: "Negate", pure]
|
||||
}
|
||||
|
||||
|
||||
operator `-`*(a: float64): float64 {
|
||||
#pragma[magic: "NegateFloat64", pure]
|
||||
}
|
||||
|
||||
|
||||
operator `-`*(a: float32): float32 {
|
||||
#pragma[magic: "NegateFloat32", pure]
|
||||
}
|
||||
|
||||
|
||||
operator `-`*(a: inf): inf {
|
||||
#pragma[magic: "NegInf", pure]
|
||||
}
|
||||
|
||||
|
||||
operator `*`*[T: int | uint64 | int32 | uint32 | int16 | uint16 | int8 | uint8](a, b: T): T {
|
||||
#pragma[magic: "Multiply", pure]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue