Skip to content

Commit

Permalink
Semantic: qualified method call static impl
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Apr 6, 2024
1 parent df56129 commit 057590d
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
dist
pnpm-lock.yaml
0x
tmp
4 changes: 2 additions & 2 deletions src/ast/operand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LexerToken } from '../lexer/lexer'
import { ParseNode, ParseTree, filterNonAstNodes } from '../parser'
import { nameLikeTokens } from '../parser/fns'
import { VirtualIdentifierMatch } from '../scope/vid'
import { Typed, Virtual } from '../semantic'
import { Static, Typed, Virtual } from '../semantic'
import { assert } from '../util/todo'
import { Expr, buildExpr } from './expr'
import { AstNode, Param, buildParam } from './index'
Expand Down Expand Up @@ -234,7 +234,7 @@ export const buildBoolLiteral = (node: ParseNode): BoolLiteral => {
return { kind: 'bool-literal', parseNode: node, value: (<LexerToken>node).value }
}

export interface Identifier extends AstNode<'identifier'>, Partial<Typed> {
export interface Identifier extends AstNode<'identifier'>, Partial<Typed>, Partial<Static> {
names: Name[]
typeArgs: Type[]
ref?: VirtualIdentifierMatch
Expand Down
5 changes: 2 additions & 3 deletions src/codegen/js/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,8 @@ export const emitOperand = (operand: Operand, module: Module, ctx: Context): Emi
})
const relName = jsRelName(operand.ref.def.rel)
const fnName = operand.ref.def.fn.name.value
const delegate = `return ${args[0].resultVar}.${relName}().${fnName}(${args.map(
a => a.resultVar
)});`
const callerEmit = operand.impl ? jsRelName(operand.impl) : `${args[0].resultVar}.${relName}`
const delegate = `return ${callerEmit}().${fnName}(${args.map(a => a.resultVar)});`
const block = `${args.map(a => (<EmitToken>a.emit).value)}${delegate}`
return {
emit: emitToken(''),
Expand Down
99 changes: 57 additions & 42 deletions src/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,40 +109,38 @@ const run = (ctx: Context): SpawnSyncReturns<Buffer> => {

describe('e2e', () => {
beforeAll(async () => {
await compileStd()
})

afterAll(() => {
rmdirSync('tmp', { recursive: true })
await compileStd()
})

afterEach(() => {
beforeEach(() => {
rmdirSync('tmp/test', { recursive: true })
rmdirSync('tmp/dist/test', { recursive: true })
})

it('minimal', async () => {
const files = { 'mod.no': 'pub fn main() {}' }
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('')
})
describe('general', () => {
it('minimal', async () => {
const files = { 'mod.no': 'pub fn main() {}' }
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('')
})

it('hello', async () => {
const files = {
'mod.no': `\
it('hello', async () => {
const files = {
'mod.no': `\
pub fn main(): Unit {
println("Hello, World!")
}`
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('Hello, World!\n')
})
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('Hello, World!\n')
})

it('example', async () => {
const files = {
'mod.no': `\
it('example', async () => {
const files = {
'mod.no': `\
use std::{ math::pi, iter::MapAdapter }
trait Area {
Expand Down Expand Up @@ -176,15 +174,15 @@ pub fn main() {
.show()
)
}`
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('[8, 478.3879062809779]\n')
})
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')

Check failure on line 179 in src/e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

error: expect(received).toEqual(expected)

Expected: "" Received: "Show(...).show is not a function\n at file:///home/runner/work/nois/nois/tmp/dist/std/list.js:1:3244\n at Object.map (file:///home/runner/work/nois/nois/tmp/dist/std/option.js:1:747)\n at Object.next (file:///home/runner/work/nois/nois/tmp/dist/std/iter/mapIter.js:1:2039)\n at Object.fromIter (file:///home/runner/work/nois/nois/tmp/dist/std/list.js:1:1462)\n at Object.collect (file:///home/runner/work/nois/nois/tmp/dist/std/iter/mod.js:1:1660)\n at Object.show (file:///home/runner/work/nois/nois/tmp/dist/std/list.js:1:3344)\n at main (file:///home/runner/work/nois/nois/tmp/dist/test/mod.js:1:2677)\n at file:///home/runner/work/nois/nois/tmp/dist/test/mod.js:1:2726\n at ModuleJob.run (node:internal/modules/esm/module_job:195:25)\n at async ModuleLoader.import (node:internal/modules/esm/loader:337:24)\n" at /home/runner/work/nois/nois/src/e2e.spec.ts:179:13
expect(res.stdout.toString()).toEqual('[8, 478.3879062809779]\n')
})

it('rule110', async () => {
const files = {
'mod.no': `\
it('rule110', async () => {
const files = {
'mod.no': `\
use std::iter::MapAdapter
pub fn main() {
Expand Down Expand Up @@ -226,18 +224,18 @@ fn fmtGen(gen: List<Bool>, total: Int): String {
.collect<String>()
pad.concat(g)
}`
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual(
' x\n xx\n xxx\n xx x\n xxxxx\n xx x\n xxx xx\n xx x xxx\n xxxxxxx x\nxx xxx\n'
)
})
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual(
' x\n xx\n xxx\n xx x\n xxxxx\n xx x\n xxx xx\n xx x xxx\n xxxxxxx x\nxx xxx\n'
)
})

describe('param destructuring', () => {
it('con pattern', async () => {
const files = {
'mod.no': `\
describe('param destructuring', () => {
it('con pattern', async () => {
const files = {
'mod.no': `\
type Foo(x: Int, y: String)
pub fn main() {
Expand All @@ -246,11 +244,28 @@ pub fn main() {
fn foo(Foo(y): Foo): String {
y
}`
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('y\n')
})
})
})

describe('method call', () => {
it('qualified', async () => {
const files = {
'mod.no': `\
use std::unwrap::Unwrap
pub fn main() {
println(Unwrap::unwrap(Some(4)).trace())
}`
}
const res = run(await compile(files))
expect(res.stderr.toString()).toEqual('')
expect(res.stdout.toString()).toEqual('y\n')
expect(res.stdout.toString()).toEqual('4\n')
})
})
})
1 change: 1 addition & 0 deletions src/semantic/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ export const checkQualifiedMethodCall = (
impl = ref.def.rel
ctx.moduleStack.at(-1)!.relImports.push(impl)
}
identifier.impl = impl

// TODO
const maps: Map<string, VirtualType>[] = []
Expand Down
6 changes: 5 additions & 1 deletion src/typecheck/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { idToVid, vidEq, vidToString } from '../scope/util'
import { VirtualIdentifier, resolveVid, typeKinds } from '../scope/vid'
import { expectedTypeError } from '../semantic/error'
import { zip } from '../util/array'
import { todo } from '../util/todo'
import { todo, unreachable } from '../util/todo'
import { holeType, selfType, unknownType } from './type'

export type VirtualType = VidType | VirtualFnType | VirtualGeneric | UnknownType | MalleableType | HoleType
Expand Down Expand Up @@ -151,13 +151,17 @@ export const genericKey = (generic: Generic, ctx: Context): string => {
return `fn_${s.def.name.value}`
case 'closure-expr':
return `closure`
default:
return unreachable()
}
case 'instance':
switch (s.def.kind) {
case 'trait-def':
return `trait_${s.def.name.value}`
case 'impl-def':
return `impl`
default:
return unreachable()
}
default:
return undefined
Expand Down

0 comments on commit 057590d

Please sign in to comment.