peon-rewrite/src/frontend/compiler/typesystem.nim

308 lines
9.4 KiB
Nim

import errors
import frontend/parser/parser
import std/tables
export ast, errors
type
IntegerSize* = enum
## Integer size enumeration
Tiny = 8
Short = 16
Long = 32
LongLong = 64
FloatSize* = enum
## Float size enumeration
Half = 32
Full = 64
TypeKind* = enum
## Enumeration of compile-time types
Integer,
Float,
String,
NaN,
Infinity,
Boolean,
Any,
Typevar,
Auto,
Byte,
Char,
Structure,
EnumEntry,
Reference,
Pointer,
Union,
Function,
Lent,
Const
Type* = ref object
## A compile-time type
# Is this a type constant?
constant*: bool
# Can it be mutated?
mutable*: bool
# Is it a compiler intrinsic?
intrinsic*: bool
# Mapping of generic names to types
genericTypes*: TableRef[string, Type]
genericValues*: TableRef[string, Type]
# Type pragmas
pragmas*: TableRef[string, Pragma]
case kind*: TypeKind
of Integer:
signed*: bool
size*: IntegerSize
of Float:
width*: FloatSize
of Infinity:
positive*: bool
of Function:
isLambda*: bool
isGenerator*: bool
isCoroutine*: bool
isAuto*: bool
parameters*: TypeSignature
returnType*: Type
unsafe*: bool
of Typevar:
wrapped*: Type
of Structure:
name*: string
fields*: TableRef[string, Type]
parent*: Type
interfaces*: seq[Type]
isEnum*: bool
of Reference, Pointer, Lent, Const:
value*: Type
of Union:
types*: seq[tuple[match: bool, kind: Type, value: Expression]]
else:
discard
WarningKind* {.pure.} = enum
## A warning enumeration type
UserWarning
NameKind* {.pure.} = enum
## A name enumeration type
Default, Var, Module
Name* = ref object
## A generic name object
# Type of the identifier (NOT of the value!)
case kind*: NameKind
of Module:
path*: string
# Full absolute path of the module,
# including the extension
absPath*: string
# Just for easier lookup, it's all
# pointers anyway
names*: TableRef[string, Name]
of NameKind.Var:
# If the variable's value is another
# name, this attribute contains its
# name object. This is useful for things
# like assigning functions to variables and
# then calling the variable like it's the
# original function
assignedName*: Name
else:
discard
# The name's identifier
ident*: IdentExpr
# Owner of the identifier (module)
module*: Name
# File where the name is declared
file*: string
# Scope depth
depth*: int
# Is this name private?
isPrivate*: bool
# The type of the name's associated
# value
valueType*: Type
# The function that "owns" this name (may be nil!)
owner*: Name
# Where is this node declared in its file?
line*: int
# The AST node associated with this node. This
# is needed because we tyoecheck function and type
# declarations only if, and when, they're actually
# used
node*: Declaration
# Who is this name exported to? (Only makes sense if isPrivate
# equals false)
exportedTo*: seq[Name]
TypeSignature* = seq[tuple[name: string, kind: Type, default: TypedExpr]]
## Our typed AST representation
TypedNode* = ref object of RootObj
## A generic typed AST node
node*: ASTNode
TypedExpr* = ref object of TypedNode
## A generic typed expression
kind*: Type
TypedUnaryExpr* = ref object of TypedExpr
## A generic typed unary expression
a*: TypedExpr
TypedBinaryExpr* = ref object of TypedUnaryExpr
## A generic typed binary expression
b*: TypedExpr
TypedIdentExpr* = ref object of TypedExpr
## A typed identifier expression
name*: Name
TypedCallExpr* = ref object of TypedExpr
## A typed function call expression
callee*: Name
args*: seq[tuple[name: string, kind: Type, default: TypedExpr]]
TypedDecl* = ref object of TypedNode
## A typed declaration node
name*: Name # The declaration's name object
TypedVarDecl* = ref object of TypedDecl
## A typed variable declaration node
init*: TypedExpr
TypedTypeDecl* = ref object of TypedDecl
## A typed type declaration node
fields*: TableRef[string, TypedExpr]
parent*: Name
interfaces*: seq[TypedTypeDecl]
TypedEnumDecl* = ref object of TypedTypeDecl
## A typed enum declaration node
enumeration*: Type
variants: seq[TypedTypeDecl]
TypedFunDecl* = ref object of TypedDecl
## A typed function declaration
args*: seq[tuple[name: Name, default: TypedExpr]]
body*: TypedBlockStmt
TypedStmt* = ref object of TypedNode
## A typed statement node
TypedExprStmt* = ref object of TypedStmt
expression*: TypedExpr
TypedBlockStmt* = ref object of TypedStmt
## A typed block statement
body*: seq[TypedNode]
TypedIfStmt* = ref object of TypedStmt
## A typed if statement node
thenBranch*: TypedBlockStmt
elseBranch*: TypedBlockStmt
condition*: TypedExpr
TypedWhileStmt* = ref object of TypedStmt
## A typed while statement node
body*: TypedBlockStmt
condition*: TypedExpr
proc newTypedNode*(node: ASTNode): TypedNode =
## Initializes a new typed node
new(result)
result.node = node
proc newTypedExpr*(node: Expression, kind: Type): TypedExpr =
## Initializes a new typed expression
result = TypedExpr(node: node, kind: kind)
proc newTypedDecl*(node: Declaration, name: Name): TypedDecl =
## Initializes a new typed declaration
result = TypedDecl(node: node, name: name)
proc newTypedTypeDecl*(node: TypeDecl, name: Name, fields: TableRef[string, TypedExpr], parent: Name): TypedTypeDecl =
## Initializes a new typed function declaration
result = TypedTypeDecl(node: node, name: name, fields: fields, parent: parent)
proc newTypedEnumDecl*(node: TypeDecl, name: Name, variants: seq[TypedTypeDecl], enumeration: Type): TypedEnumDecl =
## Initializes a new typed function declaration
result = TypedEnumDecl(node: node, name: name, variants: variants, enumeration: enumeration)
proc newTypedFunDecl*(node: FunDecl, name: Name, body: TypedBlockStmt): TypedFunDecl =
## Initializes a new typed function declaration
result = TypedFunDecl(node: node, name: name, body: body)
proc newTypedVarDecl*(node: VarDecl, name: Name, init: TypedExpr): TypedVarDecl =
## Initializes a new typed function declaration
result = TypedVarDecl(node: node, name: name, init: init)
proc newTypedIdentExpr*(node: IdentExpr, name: Name): TypedIdentExpr =
## Initializes a new typed identifier expression
result = TypedIdentExpr(node: node, name: name, kind: name.valueType)
proc newTypedUnaryExpr*(node: UnaryExpr, kind: Type, a: TypedExpr): TypedUnaryExpr =
## Initializes a new typed unary expression
result = TypedUnaryExpr(node: node, a: a, kind: kind)
proc newTypedBinaryExpr*(node: UnaryExpr, kind: Type, a, b: TypedExpr): TypedBinaryExpr =
## Initializes a new typed binary expression
result = TypedBinaryExpr(node: node, a: a, b: b, kind: kind)
proc newTypedCallExpr*(node: CallExpr, callee: Name,
args: seq[tuple[name: string, kind: Type, default: TypedExpr]]): TypedCallExpr =
## Initializes a new typed function call expression
result = TypedCallExpr(node: node, callee: callee, args: args, kind: callee.valueType.returnType)
proc newTypedBlockStmt*(node: BlockStmt, body: seq[TypedNode]): TypedBlockStmt =
## Initializes a new typed block statement
result = TypedBlockStmt(node: node, body: body)
proc newTypedWhileStmt*(node: WhileStmt, body: TypedBlockStmt, condition: TypedExpr): TypedWhileStmt =
## Initializes a new typed while statement
result = TypedWhileStmt(node: node, body: body, condition: condition)
proc newTypedIfStmt*(node: IfStmt, thenBranch, elseBranch: TypedBlockStmt, condition: TypedExpr): TypedIfStmt =
## Initializes a new typed block statement
result = TypedIfStmt(node: node, thenBranch: thenBranch,
elseBranch: elseBranch, condition: condition)
proc getName*(self: TypedNode): Name =
## Gets the name object associated with the
## given typed node, if it has any
case self.node.kind:
of identExpr:
result = TypedIdentExpr(self).name
of NodeKind.funDecl, NodeKind.varDecl, NodeKind.typeDecl:
result = TypedDecl(self).name
else:
result = nil # TODO