Skip to content

Commit

Permalink
Codegen: dynamic dispatch setup
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Mar 11, 2024
1 parent 9ab3f2f commit d74d258
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
4 changes: 3 additions & 1 deletion src/ast/operand.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LexerToken } from '../lexer/lexer'
import { ParseNode, ParseTree, filterNonAstNodes } from '../parser'
import { nameLikeTokens } from '../parser/fns'
import { InstanceRelation } from '../scope/trait'
import { VirtualIdentifierMatch } from '../scope/vid'
import { Typed } from '../semantic'
import { Expr, buildExpr } from './expr'
Expand All @@ -9,7 +10,7 @@ import { MatchExpr, Pattern, buildMatchExpr, buildNumber, buildPattern } from '.
import { Block, buildBlock } from './statement'
import { Type, buildType } from './type'

export type Operand =
export type Operand = (
| IfExpr
| IfLetExpr
| WhileExpr
Expand All @@ -24,6 +25,7 @@ export type Operand =
| FloatLiteral
| BoolLiteral
| Identifier
) & { traits?: Map<string, InstanceRelation> }

export const buildOperand = (node: ParseNode): Operand => {
const n = filterNonAstNodes(node)[0]
Expand Down
16 changes: 14 additions & 2 deletions src/codegen/js/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ export const emitUnaryExpr = (unaryExpr: UnaryExpr, module: Module, ctx: Context
const resultVar = nextVariable(ctx)
switch (unaryExpr.op.kind) {
case 'call-op':
const args = unaryExpr.op.args.map(a => emitExpr(a.expr, module, ctx))
const args = unaryExpr.op.args.map(a => {
const { emit, resultVar: res } = emitExpr(a.expr, module, ctx)
const traits = a.expr.kind === 'operand-expr' ? a.expr.operand.traits : undefined
const traitEmit = traits
? [...traits.entries()].map(([name, rel]) => `${a}.${name} = ${jsRelName(rel)}`)
: ''
return { emit: emitLines([emit, ...traitEmit]), resultVar: res }
})
const genericTypes = unaryExpr.op.generics?.map(g => emitGeneric(g, module, ctx)) ?? []
const jsArgs = [...args, ...genericTypes]
const variantDef = unaryExpr.op.variantDef
Expand Down Expand Up @@ -89,14 +96,19 @@ export const emitBinaryExpr = (binaryExpr: BinaryExpr, module: Module, ctx: Cont
? jsArgs.map(a => a.resultVar)
: [lOp.resultVar, ...jsArgs.map(a => a.resultVar)]
).join(', ')
const upcastRels = binaryExpr.lOperand.traits
const upcastEmit = upcastRels
? [...upcastRels.entries()].map(([name, rel]) => `${lOp.resultVar}.${name} = ${jsRelName(rel)}`)
: ''
return {
emit: emitLines([
lOp.emit,
...upcastEmit,
emitLines(jsArgs.map(a => a.emit)),
jsVariable(
resultVar,
`${
call.impl ? jsRelName(call.impl) : jsError('dynamic dispatch')
call.impl ? jsRelName(call.impl) : `${lOp.resultVar}.${relTypeName(methodDef.rel)}`
}().${methodName}(${argsEmit})`
)
]),
Expand Down
11 changes: 7 additions & 4 deletions src/scope/trait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const relTypeName = (rel: InstanceRelation): string => {
export const resolveGenericImpls = (generic: VirtualGeneric, ctx: Context): InstanceRelation[] => {
return generic.bounds.flatMap(b => {
const candidates = ctx.impls
.filter(i => i.instanceDef.kind === 'impl-def' && isAssignable(b, i.implType, ctx))
.filter(i => isAssignable(b, i.implType, ctx))
.toSorted((a, b) => relOrdering(b) - relOrdering(a))
return candidates.length > 0 ? [candidates.at(0)!] : []
})
Expand All @@ -219,19 +219,22 @@ export const resolveMethodImpl = (type: VirtualType, method: MethodDef, ctx: Con
const candidates = ctx.impls
.filter(
i =>
i.instanceDef.kind === 'impl-def' &&
(i.instanceDef.kind === 'impl-def' ||
i.instanceDef.block.statements.find(
s => s.kind === 'fn-def' && s.name.value === method.fn.name.value && s.block
)) &&
isAssignable(type, i.forType, ctx) &&
isAssignable(i.implType, method.rel.implType, ctx) &&
(!i.inherent ||
i.instanceDef.block.statements.find(
s => s.kind === 'fn-def' && s.name.value === method.fn.name.value
))
)
.toSorted((a, b) => relOrdering(b) - relOrdering(a))
.toSorted((a, b) => relOrdering(b, type, method.rel.forType) - relOrdering(a, type, method.rel.forType))
return candidates.at(0)
}

export const relOrdering = (rel: InstanceRelation): number => {
export const relOrdering = (rel: InstanceRelation, implType?: VirtualType, forType?: VirtualType): number => {
let score = 0
if (rel.instanceDef.kind === 'impl-def') score += 8
return score
Expand Down
10 changes: 10 additions & 0 deletions src/util/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ export const groupByHaving = <T, K>(arr: T[], keyFn: (t: T) => K, havingFn: (t:
}
return groups
}

export const zip = <A, B, C>(a: A[], b: B[], f: (a: A, b: B, i: number) => C): C[] => {
const la = a.length
const lb = b.length
const res = []
for (let i = 0; i < la && i < lb; i++) {
res.push(f(a[i], b[i], i))
}
return res
}

0 comments on commit d74d258

Please sign in to comment.