Skip to content

Commit

Permalink
started working on type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Nov 5, 2023
1 parent a010d90 commit e29c97b
Show file tree
Hide file tree
Showing 5 changed files with 326 additions and 8 deletions.
86 changes: 85 additions & 1 deletion src/ast/base_language.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import std/[tables, strformat]
import id, ast_ids, util, custom_logger
import model, cells
import ui/node

logCategory "base-language"

let typeClass* = newNodeClass(IdType, "Type", isAbstract=true)
let stringTypeClass* = newNodeClass(IdString, "StringType", alias="string", base=typeClass)
let intTypeClass* = newNodeClass(IdInt, "IntType", alias="int", base=typeClass)
Expand Down Expand Up @@ -431,6 +434,87 @@ builder.addBuilderFor buildExpressionClass.id, idNone(), proc(builder: CellBuild

return cell

var typeComputers = initTable[ClassId, proc(ctx: ModelComputationContextBase, node: AstNode): AstNode]()

let stringTypeInstance* = newAstNode(stringTypeClass)
let intTypeInstance* = newAstNode(intTypeClass)
let voidTypeInstance* = newAstNode(voidTypeClass)

# todo: those should technically return something like typeTypeInstance which needs a new typeTypeClass
# and the valueComputer should return the type instance
typeComputers[stringTypeClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for string type literal {node}"
return stringTypeInstance
typeComputers[intTypeClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for int type literal {node}"
return intTypeInstance
typeComputers[voidTypeClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for void type literal {node}"
return voidTypeInstance

# literals
typeComputers[stringLiteralClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for string type literal {node}"
return stringTypeInstance

typeComputers[numberLiteralClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for int type literal {node}"
return intTypeInstance

typeComputers[boolLiteralClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for bool type literal {node}"
return intTypeInstance

# declarations
typeComputers[letDeclClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for let decl {node}"
return voidTypeInstance

typeComputers[varDeclClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for var decl {node}"
return voidTypeInstance

typeComputers[constDeclClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for const decl {node}"
return voidTypeInstance

# control flow
typeComputers[whileClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for while loop {node}"
return voidTypeInstance

typeComputers[ifClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for if expr {node}"
return voidTypeInstance

# function definition
typeComputers[functionDefinitionClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for function definition {node}"
var returnType = voidTypeInstance

if node.firstChild(IdFunctionDefinitionReturnType).getSome(returnTypeNode):
returnType = ctx.computeType(returnTypeNode)

var functionType = newAstNode(functionTypeClass)
functionType.add(IdFunctionTypeReturnType, returnType)

for _, c in node.children(IdFunctionDefinitionParameters):
if c.firstChild(IdParameterDeclType).getSome(paramTypeNode):
# todo: This needs computeValue in the future since the type of a type is 'type', and the value is 'int' or 'string' etc.
var parameterType = ctx.computeType(paramTypeNode)
if parameterType.isNil:
# addDiagnostic(paramTypeNode, "Could not compute type for parameter")
continue
functionType.add(IdFunctionTypeParameterTypes, parameterType)

functionType.model = node.model
functionType.forEach2 n:
n.model = node.model

echo fmt"computed function type: {`$`(functionType, true)}"

return functionType

let baseLanguage* = newLanguage(IdBaseLanguage, @[
namedInterface, declarationInterface,

Expand All @@ -444,6 +528,6 @@ let baseLanguage* = newLanguage(IdBaseLanguage, @[
lessExpressionClass, lessEqualExpressionClass, greaterExpressionClass, greaterEqualExpressionClass, equalExpressionClass, notEqualExpressionClass, andExpressionClass, orExpressionClass, orderExpressionClass,
negateExpressionClass, notExpressionClass,
appendStringExpressionClass, printExpressionClass, buildExpressionClass,
], builder)
], builder, typeComputers)

# print baseLanguage
7 changes: 3 additions & 4 deletions src/ast/base_language_wasm.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

import std/[options, tables]
import id, model, ast_ids
import id, model, ast_ids, custom_logger, util, model_state
import scripting/[wasm_builder]
import custom_logger, util

logCategory "base-language-wasm"

Expand Down Expand Up @@ -67,11 +66,11 @@ proc getOrCreateWasmFunc(self: BaseLanguageWasmCompiler, node: AstNode, exportNa
if not self.wasmFuncs.contains(node.id):
var inputs, outputs: seq[WasmValueType]

for c in node.children(IdFunctionDefinitionParameters):
for _, c in node.children(IdFunctionDefinitionParameters):
let typ = c.children(IdParameterDeclType)[0]
inputs.add typ.toWasmValueType

for c in node.children(IdFunctionDefinitionReturnType):
for _, c in node.children(IdFunctionDefinitionReturnType):
outputs.add c.toWasmValueType

let funcIdx = self.builder.addFunction(inputs, outputs, exportName=exportName)
Expand Down
30 changes: 29 additions & 1 deletion src/ast/model.nim
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ type
NodeValidator* = ref object
propertyValidators*: ArrayTable[RoleId, PropertyValidator]

ModelComputationContextBase* = ref object of RootObj

Language* = ref object
id {.getter.}: LanguageId
version {.getter.}: int
Expand All @@ -144,6 +146,9 @@ type

validators: Table[ClassId, NodeValidator]

# functions for computing the type of a node
typeComputers*: Table[ClassId, proc(ctx: ModelComputationContextBase, node: AstNode): AstNode]

Model* = ref object
id {.getter.}: ModelId
rootNodes {.getter.}: seq[AstNode]
Expand All @@ -165,6 +170,10 @@ generateGetters(NodeClass)
generateGetters(Model)
generateGetters(Language)

proc hash*(node: AstNode): Hash = node.id.hash

method computeType*(self: ModelComputationContextBase, node: AstNode): AstNode {.base.} = discard

proc notifyNodeDeleted(self: Model, parent: AstNode, child: AstNode, role: RoleId, index: int) =
self.onNodeDeleted.invoke (self, parent, child, role, index)

Expand Down Expand Up @@ -212,9 +221,11 @@ proc verify*(self: Language): bool =
log(lvlError, fmt"Class {c.name} is both final and abstract")
result = false

proc newLanguage*(id: LanguageId, classes: seq[NodeClass], builder: CellBuilder): Language =
proc newLanguage*(id: LanguageId, classes: seq[NodeClass], builder: CellBuilder, typeComputers: Table[ClassId, proc(ctx: ModelComputationContextBase, node: AstNode): AstNode]): Language =
new result
result.id = id
result.typeComputers = typeComputers

for c in classes:
result.classes[c.id] = c

Expand Down Expand Up @@ -392,6 +403,21 @@ proc children*(node: AstNode, role: RoleId): seq[AstNode] =
result = c.nodes
break

iterator children*(node: AstNode, role: RoleId): (int, AstNode) =
for c in node.childLists.mitems:
if c.role == role:
for i, node in c.nodes:
yield (i, node)
break

proc firstChild*(node: AstNode, role: RoleId): Option[AstNode] =
result = AstNode.none
for c in node.childLists.mitems:
if c.role == role:
if c.nodes.len > 0:
result = c.nodes[0].some
break

proc hasReference*(node: AstNode, role: RoleId): bool =
result = false
for c in node.references:
Expand Down Expand Up @@ -766,6 +792,8 @@ method dump*(self: EmptyCell, recurse: bool = false): string =
result.add fmt"EmptyCell(node: {self.node.id})"

proc `$`*(node: AstNode, recurse: bool = false): string =
if node.isNil:
return "AstNode(nil)"
let class = node.nodeClass

if class.isNil:
Expand Down
Loading

0 comments on commit e29c97b

Please sign in to comment.