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