Skip to content

Commit

Permalink
progress on type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Nov 5, 2023
1 parent e29c97b commit 1ac64bc
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 32 deletions.
128 changes: 127 additions & 1 deletion src/ast/base_language.nim
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,140 @@ typeComputers[functionDefinitionClass.id] = proc(ctx: ModelComputationContextBas
continue
functionType.add(IdFunctionTypeParameterTypes, parameterType)

# todo: this shouldn't set the model
functionType.model = node.model
functionType.forEach2 n:
n.model = node.model

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

return functionType

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

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

typeComputers[nodeListClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for node list {node}"

if node.firstChild(IdNodeListChildren).getSome(childNode):
return ctx.computeType(childNode)

return voidTypeInstance

typeComputers[blockClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for block {node}"

if node.firstChild(IdBlockChildren).getSome(childNode):
return ctx.computeType(childNode)

return voidTypeInstance

typeComputers[nodeReferenceClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for node reference {node}"
# todo
return voidTypeInstance

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

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

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

# binary expressions
typeComputers[addExpressionClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for add {node}"
return voidTypeInstance

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

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

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

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

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

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

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

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

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

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

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

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

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

# unary expressions
typeComputers[negateExpressionClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for negate {node}"
return voidTypeInstance

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

# calls
typeComputers[callClass.id] = proc(ctx: ModelComputationContextBase, node: AstNode): AstNode =
debugf"compute type for call {node}"
# todo
return voidTypeInstance

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

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

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

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

Expand Down
5 changes: 4 additions & 1 deletion src/ast/base_language_wasm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type
BaseLanguageWasmCompiler* = ref object
builder: WasmBuilder

ctx: ModelComputationContextBase

wasmFuncs: Table[Id, WasmFuncIdx]

functionsToCompile: seq[(AstNode, WasmFuncIdx)]
Expand All @@ -27,10 +29,11 @@ type

proc setupGenerators(self: BaseLanguageWasmCompiler)

proc newBaseLanguageWasmCompiler*(): BaseLanguageWasmCompiler =
proc newBaseLanguageWasmCompiler*(ctx: ModelComputationContextBase): BaseLanguageWasmCompiler =
new result
result.setupGenerators()
result.builder = newWasmBuilder()
result.ctx = ctx

result.builder.mems.add(WasmMem(typ: WasmMemoryType(limits: WasmLimits(min: 255))))

Expand Down
62 changes: 43 additions & 19 deletions src/ast/model.nim
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ type
id {.getter.}: LanguageId
version {.getter.}: int
classes {.getter.}: Table[ClassId, NodeClass]
childClasses {.getter.}: Table[ClassId, seq[NodeClass]]
# childClasses {.getter.}: Table[ClassId, seq[NodeClass]]
builder {.getter.}: CellBuilder

validators: Table[ClassId, NodeValidator]
Expand All @@ -155,6 +155,7 @@ type
languages {.getter.}: seq[Language]
importedModels {.getter.}: seq[Model]
classesToLanguages {.getter.}: Table[ModelId, Language]
childClasses {.getter.}: Table[ClassId, seq[NodeClass]]
nodes {.getter.}: Table[NodeId, AstNode]

onNodeDeleted*: Event[tuple[self: Model, parent: AstNode, child: AstNode, role: RoleId, index: int]]
Expand Down Expand Up @@ -229,19 +230,19 @@ proc newLanguage*(id: LanguageId, classes: seq[NodeClass], builder: CellBuilder,
for c in classes:
result.classes[c.id] = c

if c.base.isNotNil:
if not result.childClasses.contains(c.base.id):
result.childClasses[c.base.id] = @[]
result.childClasses[c.base.id].add c
# if c.base.isNotNil:
# if not result.childClasses.contains(c.base.id):
# result.childClasses[c.base.id] = @[]
# result.childClasses[c.base.id].add c

for i in c.interfaces:
if not result.childClasses.contains(i.id):
result.childClasses[i.id] = @[]
result.childClasses[i.id].add c
# for i in c.interfaces:
# if not result.childClasses.contains(i.id):
# result.childClasses[i.id] = @[]
# result.childClasses[i.id].add c

result.builder = builder

proc forEachChildClass*(self: Language, base: NodeClass, handler: proc(c: NodeClass)) =
proc forEachChildClass*(self: Model, base: NodeClass, handler: proc(c: NodeClass)) =
handler(base)
if self.childClasses.contains(base.id):
for c in self.childClasses[base.id]:
Expand All @@ -267,10 +268,23 @@ proc addModel*(self: Project, model: Model) =
proc addLanguage*(self: Model, language: Language) =
if not language.verify():
return

self.languages.add language

for c in language.classes.keys:
self.classesToLanguages[c] = language

for c in language.classes.values:
if c.base.isNotNil:
if not self.childClasses.contains(c.base.id):
self.childClasses[c.base.id] = @[]
self.childClasses[c.base.id].add c

for i in c.interfaces:
if not self.childClasses.contains(i.id):
self.childClasses[i.id] = @[]
self.childClasses[i.id].add c

proc addRootNode*(self: Model, node: AstNode) =
self.rootNodes.add node
# node.forEach proc(n: AstNode) =
Expand Down Expand Up @@ -418,6 +432,14 @@ proc firstChild*(node: AstNode, role: RoleId): Option[AstNode] =
result = c.nodes[0].some
break

proc lastChild*(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.last.some
break

proc hasReference*(node: AstNode, role: RoleId): bool =
result = false
for c in node.references:
Expand Down Expand Up @@ -508,28 +530,30 @@ proc newAstNode*(class: NodeClass, id: Option[NodeId] = NodeId.none): AstNode =
result.class = class.id
result.addMissingFieldsForClass(class)

proc isUnique*(language: Language, class: NodeClass): bool =
proc isUnique*(model: Model, class: NodeClass): bool =
if class.isFinal:
return true
if not language.childClasses.contains(class.id):
if not model.childClasses.contains(class.id):
return true
return false

proc fillDefaultChildren*(node: AstNode, language: Language, onlyUnique: bool = false) =
proc fillDefaultChildren*(node: AstNode, model: Model, onlyUnique: bool = false) =
let language = model.classesToLanguages.getOrDefault(node.class, nil)
let class = language.classes.getOrDefault(node.class, nil)

for desc in class.children:
if desc.count in {ChildCount.One, ChildCount.OneOrMore}:
let childClass = language.classes.getOrDefault(desc.class)
if childClass.isNil:
log lvlError, fmt"Unknown class {desc.class}"
continue

let isUnique = language.isUnique(childClass)
let isUnique = model.isUnique(childClass)
if onlyUnique and not isUnique:
continue

let child = newAstNode(childClass)
child.fillDefaultChildren(language, onlyUnique)
child.fillDefaultChildren(model, onlyUnique)
node.add(desc.id, child)

proc ancestor*(node: AstNode, distance: int): AstNode =
Expand Down Expand Up @@ -713,7 +737,7 @@ proc replaceWithDefault*(node: AstNode, fillDefaultChildren: bool = false): Opti

var child = newAstNode(node.model.resolveClass(desc.class))
if fillDefaultChildren:
child.fillDefaultChildren(node.language)
child.fillDefaultChildren(node.model)

# debugf"replaceWithDefault: replacing {node} with {child}"
node.parent.replace(node.role, node.index, child)
Expand All @@ -730,7 +754,7 @@ proc deleteOrReplaceWithDefault*(node: AstNode, fillDefaultChildren: bool = fals
if desc.count in {One, OneOrMore} and node.parent.childCount(node.role) == 1:
var child = newAstNode(node.model.resolveClass(desc.class))
if fillDefaultChildren:
child.fillDefaultChildren(node.language)
child.fillDefaultChildren(node.model)

# debugf"deleteOrReplaceWithDefault: replacing {node} with {child}"
node.parent.replace(node.role, node.index, child)
Expand All @@ -748,7 +772,7 @@ proc insertDefaultNode*(node: AstNode, role: RoleId, index: int, fillDefaultChil
let class = node.nodeClass
let desc = class.nodeChildDescription(role).get

let language = node.language
let language = node.model.classesToLanguages.getOrDefault(desc.class, nil)
if language.isNil:
return

Expand All @@ -758,7 +782,7 @@ proc insertDefaultNode*(node: AstNode, role: RoleId, index: int, fillDefaultChil

var child = newAstNode(childClass)
if fillDefaultChildren:
child.fillDefaultChildren(language)
child.fillDefaultChildren(node.model)

node.insert(role, index, child)

Expand Down
21 changes: 10 additions & 11 deletions src/model_document.nim
Original file line number Diff line number Diff line change
Expand Up @@ -563,16 +563,15 @@ proc updateCompletions(self: ModelDocumentEditor) =

debugf"updateCompletions {node}, {node.model.isNotNil}, {slotClass.name}"

for language in model.languages:
language.forEachChildClass slotClass, proc(childClass: NodeClass) =
if self.getSubstitutionsForClass(targetCell, childClass, (c) -> void => self.unfilteredCompletions.add(c)):
return
model.forEachChildClass slotClass, proc(childClass: NodeClass) =
if self.getSubstitutionsForClass(targetCell, childClass, (c) -> void => self.unfilteredCompletions.add(c)):
return

if childClass.isAbstract or childClass.isInterface:
return
if childClass.isAbstract or childClass.isInterface:
return

let name = if childClass.alias.len > 0: childClass.alias else: childClass.name
self.unfilteredCompletions.add ModelCompletion(kind: ModelCompletionKind.SubstituteClass, name: name, class: childClass, parent: parent, role: role, index: index)
let name = if childClass.alias.len > 0: childClass.alias else: childClass.name
self.unfilteredCompletions.add ModelCompletion(kind: ModelCompletionKind.SubstituteClass, name: name, class: childClass, parent: parent, role: role, index: index)

self.refilterCompletions()
self.markDirty()
Expand Down Expand Up @@ -2473,7 +2472,7 @@ proc applySelectedCompletion*(self: ModelDocumentEditor) {.expose("editor.model"
parent.remove(role, index)

var newNode = newAstNode(completion.class)
newNode.fillDefaultChildren(parent.language, true)
newNode.fillDefaultChildren(parent.model, true)
parent.insert(role, index, newNode)
self.rebuildCells()
self.cursor = self.getFirstEditableCellOfNode(newNode).get
Expand Down Expand Up @@ -2522,7 +2521,7 @@ proc runSelectedFunctionAsync*(self: ModelDocumentEditor): Future[void] {.async.
self.document.ctx.state.updateNode(function.get)

let typ = self.document.ctx.computeType(function.get)
echo `$`(typ, true)
log lvlDebug, `$`(typ, true)

if function.get.childCount(IdFunctionDefinitionParameters) > 0:
log(lvlError, fmt"Can't call function with parameters")
Expand All @@ -2535,7 +2534,7 @@ proc runSelectedFunctionAsync*(self: ModelDocumentEditor): Future[void] {.async.
"<anonymous>"

measureBlock fmt"Compile '{name}' to wasm":
var compiler = newBaseLanguageWasmCompiler()
var compiler = newBaseLanguageWasmCompiler(self.document.ctx)
let binary = compiler.compileToBinary(function.get)

if self.document.workspace.getSome(workspace):
Expand Down

0 comments on commit 1ac64bc

Please sign in to comment.