Updated compiler error messages and Generic type object, minor name changes

This commit is contained in:
Mattia Giambirtone 2022-10-11 09:56:55 +02:00
parent 9ef80535f3
commit c168d1584b
1 changed files with 43 additions and 44 deletions

View File

@ -69,7 +69,7 @@ type
of Reference, Pointer: of Reference, Pointer:
value: Type value: Type
of Generic: of Generic:
node: IdentExpr cond: Expression
else: else:
discard discard
@ -207,8 +207,9 @@ 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) proc varDecl(self: Compiler, node: VarDecl)
proc inferType(self: Compiler, node: LiteralExpr): Type proc matchImpl(self: Compiler, name: string, kind: Type): Name
proc inferType(self: Compiler, node: Expression): Type proc infer(self: Compiler, node: LiteralExpr): Type
proc infer(self: Compiler, node: Expression): Type
proc findByName(self: Compiler, name: string): seq[Name] proc findByName(self: Compiler, name: string): seq[Name]
proc findByType(self: Compiler, name: string, kind: Type, depth: int = -1): seq[Name] proc findByType(self: Compiler, name: string, kind: Type, depth: int = -1): seq[Name]
proc compareTypes(self: Compiler, a, b: Type): bool proc compareTypes(self: Compiler, a, b: Type): bool
@ -618,7 +619,7 @@ proc toIntrinsic(name: string): Type =
return nil return nil
proc inferType(self: Compiler, node: LiteralExpr): Type = proc infer(self: Compiler, node: LiteralExpr): Type =
## Infers the type of a given literal expression ## Infers the type of a given literal expression
if node.isNil(): if node.isNil():
return nil return nil
@ -660,10 +661,8 @@ proc inferType(self: Compiler, node: LiteralExpr): Type =
else: else:
discard # TODO discard # TODO
proc matchImpl(self: Compiler, name: string, kind: Type): Name
proc infer(self: Compiler, node: Expression): Type =
proc inferType(self: Compiler, node: Expression): Type =
## Infers the type of a given expression and ## Infers the type of a given expression and
## returns it ## returns it
if node.isNil(): if node.isNil():
@ -678,22 +677,22 @@ proc inferType(self: Compiler, node: Expression): Type =
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.inferType(node.a))])).valueType.returnType return self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(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.inferType(node.a)), ("", self.inferType(node.b))])).valueType.returnType return self.matchImpl(node.operator.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", self.infer(node.a)), ("", self.infer(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.inferType(LiteralExpr(node)) return 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)
if not node.returnType.isNil(): if not node.returnType.isNil():
result.returnType = self.inferType(node.returnType) result.returnType = self.infer(node.returnType)
for argument in node.arguments: for argument in node.arguments:
result.args.add((argument.name.token.lexeme, self.inferType(argument.valueType))) result.args.add((argument.name.token.lexeme, self.infer(argument.valueType)))
of callExpr: of callExpr:
var node = CallExpr(node) var node = CallExpr(node)
case node.callee.kind: case node.callee.kind:
@ -704,27 +703,27 @@ proc inferType(self: Compiler, node: Expression): Type =
else: else:
result = nil result = nil
of lambdaExpr: of lambdaExpr:
result = self.inferType(LambdaExpr(node.callee).returnType) result = self.infer(LambdaExpr(node.callee).returnType)
of callExpr: of callExpr:
result = self.inferType(CallExpr(node.callee)) result = self.infer(CallExpr(node.callee))
if not result.isNil(): if not result.isNil():
result = result.returnType result = result.returnType
else: else:
discard # Unreachable discard # Unreachable
of varExpr: of varExpr:
result = self.inferType(Var(node).value) result = self.infer(Var(node).value)
result.mutable = true result.mutable = true
of refExpr: of refExpr:
result = Type(kind: Reference, value: self.inferType(Ref(node).value)) result = Type(kind: Reference, value: self.infer(Ref(node).value))
of ptrExpr: of ptrExpr:
result = Type(kind: Pointer, value: self.inferType(Ptr(node).value)) result = Type(kind: Pointer, value: self.infer(Ptr(node).value))
of groupingExpr: of groupingExpr:
result = self.inferType(GroupingExpr(node).expression) result = self.infer(GroupingExpr(node).expression)
else: else:
discard # Unreachable discard # Unreachable
proc inferType(self: Compiler, node: Declaration, strictMutable: bool = true): Type = proc infer(self: Compiler, node: Declaration, strictMutable: bool = true): Type =
## Infers the type of a given declaration ## Infers the type of a given declaration
## and returns it ## and returns it
if node.isNil(): if node.isNil():
@ -741,7 +740,7 @@ proc inferType(self: Compiler, node: Declaration, strictMutable: bool = true): T
if not resolved.isNil(): if not resolved.isNil():
return resolved.valueType return resolved.valueType
else: else:
return self.inferType(node.value, strictMutable) return self.infer(node.value, strictMutable)
else: else:
return # Unreachable return # Unreachable
@ -774,7 +773,7 @@ proc typeToStr(self: Compiler, typ: Type): string =
if not typ.returnType.isNil(): if not typ.returnType.isNil():
result &= &": {self.typeToStr(typ.returnType)}" result &= &": {self.typeToStr(typ.returnType)}"
of Generic: of Generic:
result = typ.node.name.lexeme result = &"T: {typ.cond}"
else: else:
discard discard
@ -816,7 +815,7 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
var msg = &"cannot find a suitable implementation for '{name}'" var msg = &"cannot find a suitable implementation for '{name}'"
let names = self.findByName(name) let names = self.findByName(name)
if names.len() > 0: if names.len() > 0:
msg &= &", found {len(names)} candidate" msg &= &", found {len(names)} potential candidate"
if names.len() > 1: if names.len() > 1:
msg &= "s" msg &= "s"
msg &= ": " msg &= ": "
@ -838,7 +837,7 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
elif impl.len() > 1: elif impl.len() > 1:
var msg = &"multiple matching implementations of '{name}' found:\n" var msg = &"multiple matching implementations of '{name}' found:\n"
for fn in reversed(impl): for fn in reversed(impl):
msg &= &"- '{fn.name.token.lexeme}' in '{fn.owner}' at line {fn.line} of type {self.typeToStr(fn.valueType)}\n" msg &= &"- '{fn.name.token.lexeme}' in module '{fn.owner}' at line {fn.line} of type {self.typeToStr(fn.valueType)}\n"
self.error(msg) self.error(msg)
return impl[0] return impl[0]
@ -847,7 +846,7 @@ proc check(self: Compiler, term: Expression, kind: Type) =
## Checks the type of term against a known type. ## Checks the type of term against a known type.
## Raises an error if appropriate and returns ## Raises an error if appropriate and returns
## otherwise ## otherwise
let k = self.inferType(term) let k = self.infer(term)
if k.isNil(): if k.isNil():
if term.kind == identExpr: if term.kind == identExpr:
self.error(&"reference to undeclared name '{term.token.lexeme}'", term) self.error(&"reference to undeclared name '{term.token.lexeme}'", term)
@ -1154,7 +1153,7 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
isPrivate: node.isPrivate, isPrivate: node.isPrivate,
owner: self.currentModule, owner: self.currentModule,
isConst: node.isConst, isConst: node.isConst,
valueType: self.inferType(node.value), valueType: self.infer(node.value),
codePos: self.chunk.code.len(), codePos: self.chunk.code.len(),
isLet: node.isLet, isLet: node.isLet,
line: node.token.line, line: node.token.line,
@ -1172,7 +1171,7 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
isConst: false, isConst: false,
owner: self.currentModule, owner: self.currentModule,
line: node.token.line, line: node.token.line,
valueType: Type(kind: Generic, mutable: false, node: gen.name), valueType: Type(kind: Generic, mutable: false, cond: gen.cond),
name: gen.name)) name: gen.name))
self.names.add(Name(depth: self.scopeDepth, self.names.add(Name(depth: self.scopeDepth,
isPrivate: node.isPrivate, isPrivate: node.isPrivate,
@ -1180,7 +1179,7 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
owner: self.currentModule, owner: self.currentModule,
valueType: Type(kind: Function, valueType: Type(kind: Function,
name: node.name.token.lexeme, name: node.name.token.lexeme,
returnType: self.inferType(node.returnType), returnType: self.infer(node.returnType),
args: @[], args: @[],
fun: node, fun: node,
children: @[]), children: @[]),
@ -1211,7 +1210,7 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
belongsTo: fn belongsTo: fn
) )
self.names.add(name) self.names.add(name)
name.valueType = self.inferType(argument.valueType) name.valueType = self.infer(argument.valueType)
# If it's still nil, it's an error! # If it's still nil, it's an error!
if name.valueType.isNil(): if name.valueType.isNil():
self.error(&"cannot determine the type of argument '{argument.name.token.lexeme}'", argument.name) self.error(&"cannot determine the type of argument '{argument.name.token.lexeme}'", argument.name)
@ -1291,7 +1290,7 @@ proc fixGenericFunc(self: Compiler, name: Name, args: seq[Expression]): Name =
var typ: Type var typ: Type
for i in 0..args.high(): for i in 0..args.high():
if fn.valueType.args[i].kind.kind == Generic: if fn.valueType.args[i].kind.kind == Generic:
typ = self.inferType(args[i]) typ = self.infer(args[i])
fn.valueType.args[i].kind = typ fn.valueType.args[i].kind = typ
self.resolve(fn.valueType.args[i].name).valueType = typ self.resolve(fn.valueType.args[i].name).valueType = typ
if fn.valueType.args[i].kind.isNil(): if fn.valueType.args[i].kind.isNil():
@ -1381,7 +1380,7 @@ proc literal(self: Compiler, node: ASTNode) =
self.emitConstant(LiteralExpr(node), Type(kind: String)) self.emitConstant(LiteralExpr(node), Type(kind: String))
of intExpr: of intExpr:
let y = IntExpr(node) let y = IntExpr(node)
let kind = self.inferType(y) let kind = self.infer(y)
if kind.kind in [Int64, Int32, Int16, Int8]: if kind.kind in [Int64, Int32, Int16, Int8]:
var x: int var x: int
try: try:
@ -1407,7 +1406,7 @@ proc literal(self: Compiler, node: ASTNode) =
stop: y.token.pos.start + len($x)) stop: y.token.pos.start + len($x))
) )
) )
self.emitConstant(node, self.inferType(y)) self.emitConstant(node, self.infer(y))
of binExpr: of binExpr:
var x: int var x: int
var y = BinExpr(node) var y = BinExpr(node)
@ -1420,7 +1419,7 @@ proc literal(self: Compiler, node: ASTNode) =
stop: y.token.pos.start + len($x)) stop: y.token.pos.start + len($x))
) )
) )
self.emitConstant(node, self.inferType(y)) self.emitConstant(node, self.infer(y))
of octExpr: of octExpr:
var x: int var x: int
var y = OctExpr(node) var y = OctExpr(node)
@ -1433,7 +1432,7 @@ proc literal(self: Compiler, node: ASTNode) =
stop: y.token.pos.start + len($x)) stop: y.token.pos.start + len($x))
) )
) )
self.emitConstant(node, self.inferType(y)) self.emitConstant(node, self.infer(y))
of floatExpr: of floatExpr:
var x: float var x: float
var y = FloatExpr(node) var y = FloatExpr(node)
@ -1441,7 +1440,7 @@ proc literal(self: Compiler, node: ASTNode) =
discard parseFloat(y.literal.lexeme, x) discard parseFloat(y.literal.lexeme, x)
except ValueError: except ValueError:
self.error("floating point value out of range") self.error("floating point value out of range")
self.emitConstant(y, self.inferType(y)) self.emitConstant(y, self.infer(y))
of awaitExpr: of awaitExpr:
var y = AwaitExpr(node) var y = AwaitExpr(node)
self.expression(y.expression) self.expression(y.expression)
@ -1463,15 +1462,15 @@ proc callBinaryOp(self: Compiler, fn: Name, op: BinaryExpr) =
proc unary(self: Compiler, node: UnaryExpr) = proc unary(self: Compiler, node: UnaryExpr) =
## Compiles unary expressions such as decimal ## Compiles unary expressions such as decimal
## and bitwise negation ## and bitwise negation
let valueType = self.inferType(node.a) let valueType = self.infer(node.a)
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", valueType)])) let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", valueType)]))
self.callUnaryOp(funct, node) self.callUnaryOp(funct, node)
proc binary(self: Compiler, node: BinaryExpr) = proc binary(self: Compiler, node: BinaryExpr) =
## Compiles all binary expressions ## Compiles all binary expressions
let typeOfA = self.inferType(node.a) let typeOfA = self.infer(node.a)
let typeOfB = self.inferType(node.b) let typeOfB = self.infer(node.b)
let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)])) let funct = self.matchImpl(node.token.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: @[("", typeOfA), ("", typeOfB)]))
self.callBinaryOp(funct, node) self.callBinaryOp(funct, node)
@ -1484,7 +1483,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
elif s.isConst: elif s.isConst:
# Constants are always emitted as Load* instructions # Constants are always emitted as Load* instructions
# no matter the scope depth # no matter the scope depth
self.emitConstant(node, self.inferType(node)) self.emitConstant(node, self.infer(node))
else: else:
if s.valueType.kind == Function and s.isFunDecl: if s.valueType.kind == Function and s.isFunDecl:
# Functions have no runtime # Functions have no runtime
@ -1556,7 +1555,7 @@ proc assignment(self: Compiler, node: ASTNode) =
self.emitBytes(self.getClosurePos(r).toTriple(), node.token.line) self.emitBytes(self.getClosurePos(r).toTriple(), node.token.line)
of setItemExpr: of setItemExpr:
let node = SetItemExpr(node) let node = SetItemExpr(node)
let typ = self.inferType(node) let typ = self.infer(node)
if typ.isNil(): if typ.isNil():
self.error(&"cannot determine the type of '{node.name.token.lexeme}'") self.error(&"cannot determine the type of '{node.name.token.lexeme}'")
# TODO # TODO
@ -1611,7 +1610,7 @@ proc callExpr(self: Compiler, node: CallExpr): Name {.discardable.} =
self.error(&"cannot make sure that call is side-effect free") self.error(&"cannot make sure that call is side-effect free")
# TODO: Keyword arguments # TODO: Keyword arguments
for i, argument in node.arguments.positionals: for i, argument in node.arguments.positionals:
kind = self.inferType(argument) kind = self.infer(argument)
if kind.isNil(): if kind.isNil():
if argument.kind == identExpr: if argument.kind == identExpr:
self.error(&"reference to undeclared name '{IdentExpr(argument).name.lexeme}'") self.error(&"reference to undeclared name '{IdentExpr(argument).name.lexeme}'")
@ -1646,7 +1645,7 @@ proc callExpr(self: Compiler, node: CallExpr): Name {.discardable.} =
discard # TODO: Lambdas discard # TODO: Lambdas
# TODO: Calling lambdas on-the-fly (i.e. on the same line) # TODO: Calling lambdas on-the-fly (i.e. on the same line)
else: else:
let typ = self.inferType(node) let typ = self.infer(node)
if typ.isNil(): if typ.isNil():
self.error(&"expression has no type") self.error(&"expression has no type")
else: else:
@ -1799,7 +1798,7 @@ proc statement(self: Compiler, node: Statement) =
case node.kind: case node.kind:
of exprStmt: of exprStmt:
let expression = ExprStmt(node).expression let expression = ExprStmt(node).expression
let kind = self.inferType(expression) let kind = self.infer(expression)
self.expression(expression) self.expression(expression)
if kind.isNil(): if kind.isNil():
# The expression has no type and produces no value, # The expression has no type and produces no value,
@ -1880,8 +1879,8 @@ proc statement(self: Compiler, node: Statement) =
proc varDecl(self: Compiler, node: VarDecl) = proc varDecl(self: Compiler, node: VarDecl) =
## Compiles variable declarations ## Compiles variable declarations
let expected = self.inferType(node.valueType) let expected = self.infer(node.valueType)
let actual = self.inferType(node.value) let actual = self.infer(node.value)
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