Skip to content

Commit

Permalink
Codegen: Trace auto implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Mar 23, 2024
1 parent cae56d4 commit 50b3d7f
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/codegen/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export interface JsImport {
}

export const emitModule = (module: Module, ctx: Context, mainFn?: string): EmitNode => {
const imports = emitImports(module, ctx)
const statements = emitTree(
module.block.statements.map(s => emitStatement(s, module, ctx)).map(s => ('resultVar' in s ? s.emit : s))
)
Expand All @@ -26,6 +25,7 @@ export const emitModule = (module: Module, ctx: Context, mainFn?: string): EmitN
`try{${mainFn}();}catch(e){console.error(\`\${e.message}\\n\${e.stack.split("\\n").slice(1).join("\\n")}\`);}`
)
: undefined
const imports = emitImports(module, ctx)
return emitTree([imports, statements, mainFnInvoke])
}

Expand Down
41 changes: 41 additions & 0 deletions src/codegen/js/native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { extractValue, jsRelName, nextVariable } from '.'
import { Module } from '../../ast'
import { Context } from '../../scope'
import { trace } from '../../scope/std'
import { InstanceRelation, resolveTypeImpl } from '../../scope/trait'
import { todo } from '../../util/todo'
import { EmitNode, emitToken, emitTree, jsVariable } from './node'

export const emitTraceImpl = (rel: InstanceRelation, module: Module, ctx: Context): EmitNode => {
const typeDef = rel.forDef.def
if (typeDef.kind === 'trait-def') {
return todo('default Trace for trait type')
}
const variants = typeDef.variants.map(v => {
const fields = v.fieldDefs.map(f => {
const impl = resolveTypeImpl(f.type!, trace, ctx)
if (impl) {
ctx.moduleStack.at(-1)!.relImports.push(impl.impl)
}
const fAccess = `${extractValue('self')}.${f.name.value}`
const fieldTraceCall = impl
? `${jsRelName(impl.impl)}().trace(${fAccess})`
: `${fAccess}.Trace().trace(${fAccess})`
return `"${f.name.value}: "+${extractValue(fieldTraceCall)}`
})
const variantStr =
fields.length > 0 ? [`"${v.name.value}("`, fields.join('+", "+'), '")"'].join('+') : `"${v.name.value}()"`
return `if(self.$noisVariant==="${v.name.value}"){return String.String(${variantStr});}`
})
const fnStr = `function(self){${variants.join('')}}`
const fnBodyEmit = emitToken(`trace: ${fnStr}`)
const fnEmit = emitTree([emitToken('{'), fnBodyEmit, emitToken('};')])

const cached = nextVariable(ctx)
const instanceEmit = emitTree([
emitToken(`function(){if(${cached}){return ${cached};}${cached}=`),
fnEmit,
emitToken(`return ${cached};}`)
])
return emitTree([jsVariable(cached), jsVariable(jsRelName(rel), instanceEmit, true)])
}
17 changes: 11 additions & 6 deletions src/codegen/js/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { Module } from '../../ast'
import { Block, BreakStmt, FnDef, ImplDef, ReturnStmt, Statement, TraitDef, VarDef } from '../../ast/statement'
import { TypeDef, Variant } from '../../ast/type-def'
import { Context } from '../../scope'
import { trace } from '../../scope/std'
import { typeDefToVirtualType } from '../../scope/trait'
import { vidToString } from '../../scope/util'
import { vidEq, vidToString } from '../../scope/util'
import { EmitExpr, emitExpr, emitParam, emitPattern } from './expr'
import { emitTraceImpl } from './native'
import { EmitNode, emitIntersperse, emitToken, emitTree, jsVariable } from './node'

export const emitStatement = (statement: Statement, module: Module, ctx: Context): EmitNode | EmitExpr => {
Expand Down Expand Up @@ -54,8 +56,11 @@ export const emitFnDef = (fnDef: FnDef, module: Module, ctx: Context, asProperty

export const emitInstanceDef = (instanceDef: ImplDef | TraitDef, module: Module, ctx: Context): EmitNode => {
const rel = ctx.impls.find(i => i.instanceDef === instanceDef)!
if (vidEq(rel.implDef.vid, trace.identifier) && instanceDef.block.statements.length === 0) {
return emitTraceImpl(rel, module, ctx)
}
const superMethods = instanceDef.kind === 'impl-def' ? instanceDef.superMethods ?? [] : []
const ms = superMethods.map(m => {
const superMs = superMethods.map(m => {
const params = m.fn.params.map((p, i) => {
const pVar = nextVariable(ctx)
const upcastMap = m.paramUpcasts ? m.paramUpcasts[i] : undefined
Expand All @@ -73,18 +78,18 @@ export const emitInstanceDef = (instanceDef: ImplDef | TraitDef, module: Module,
])
return emitTree([emitToken(`${mName}:function(${params.map(p => p.resultVar).join(',')}) `), block])
})
const fns = instanceDef.block.statements
const ms = instanceDef.block.statements
.map(s => <FnDef>s)
.map(f => emitFnDef(f, module, ctx, true))
.filter(f => f)
.map(f => f!)
const all = [...ms, ...fns]
const all = [...superMs, ...ms]
const generics = instanceDef.generics.map(g => g.name.value)
const cached = nextVariable(ctx)
const fnEmit = emitTree([emitToken('{'), emitIntersperse(all, ','), emitToken('};')])
const methodEmit = emitTree([emitToken('{'), emitIntersperse(all, ','), emitToken('};')])
const instanceEmit = emitTree([
emitToken(`function(${generics.join(',')}){if(${cached}){return ${cached};}${cached}=`),
fnEmit,
methodEmit,
emitToken(`return ${cached};}`)
])
return emitTree([jsVariable(cached), jsVariable(jsRelName(rel), instanceEmit, true)])
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ if (config.emit) {
console.info(`copy: ${packageInfoSrc} -> ${packageInfoDest}`)
pkg.modules.forEach(async m => {
ctx.variableCounter = 0
ctx.moduleStack.push(m)
const modulePath = relative(config.srcPath, m.source.filepath)
const moduleOutPath = parse(join(config.outPath, modulePath))
mkdirSync(moduleOutPath.dir, { recursive: true })
Expand Down
3 changes: 3 additions & 0 deletions src/scope/std.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ export const preludeVid = vidFromString('std::prelude')

export const bool: VidType = { kind: 'vid-type', identifier: vidFromString('std::bool::Bool'), typeArgs: [] }
export const string: VidType = { kind: 'vid-type', identifier: vidFromString('std::string::String'), typeArgs: [] }

export const show: VidType = { kind: 'vid-type', identifier: vidFromString('std::io::show::Show'), typeArgs: [] }
export const trace: VidType = { kind: 'vid-type', identifier: vidFromString('std::io::trace::Trace'), typeArgs: [] }

export const iter: VidType = { kind: 'vid-type', identifier: vidFromString('std::iter::Iter'), typeArgs: [unknownType] }
export const iterable: VidType = {
kind: 'vid-type',
Expand Down
6 changes: 5 additions & 1 deletion src/std/bool.no
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ impl Show for Bool {
}
}

impl Trace for Bool {}
impl Trace for Bool {
fn trace(self): String {
self.show()
}
}

impl Eq for Bool {
fn eq(self, other: Self): Bool {
Expand Down
6 changes: 5 additions & 1 deletion src/std/char.no
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ impl Show for Char {
}
}

impl Trace for Char {}
impl Trace for Char {
fn trace(self): String {
self.show()
}
}

impl Eq for Char {
fn eq(self, other: Self): Bool {
Expand Down
8 changes: 6 additions & 2 deletions src/std/float.no
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ impl Show for Float {
}
}

impl Trace for Float {}
impl Trace for Float {
fn trace(self): String {
self.show()
}
}

impl Copy for Int {
impl Copy for Float {
fn copy(self): Self {
copy(self)
}
Expand Down
6 changes: 5 additions & 1 deletion src/std/int.no
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ impl Show for Int {
}
}

impl Trace for Int {}
impl Trace for Int {
fn trace(self): String {
self.show()
}
}

impl Copy for Int {
fn copy(self): Self {
Expand Down
33 changes: 0 additions & 33 deletions src/std/io/trace.js

This file was deleted.

3 changes: 1 addition & 2 deletions src/std/io/trace.no
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
pub trait Trace {
fn trace(self): String {
trace(self)
panic("default impl of `Trace::trace` is created for each implementing type by the compiler")
}
}

fn trace<T>(value: T): String
11 changes: 7 additions & 4 deletions src/std/list.no
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ impl Show for List<String> {

impl <T: Show> Show for List<T> {
fn show(self): String {
// TODO: method ref
self.iter().map(|d| { d.show() }).collect<List<String>>().show()
self.iter().map(Show::show).collect<List<String>>().show()
}
}

impl <T: Trace> Trace for List<T> {}
impl <T: Trace> Trace for List<T> {
fn trace(self): String {
"[{self.iter().map(Trace::trace).intersperse(", ").collect<String>()}]"
}
}

impl Copy for Int {
impl <T: Copy> Copy for List<T> {
fn copy(self): Self {
copy(self)
}
Expand Down
8 changes: 6 additions & 2 deletions src/std/string.no
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ impl Show for String {
}
}

impl Trace for String {}
impl Trace for String {
fn trace(self): String {
self
}
}

impl Eq for String {
fn eq(self, other: Self): Bool {
Expand All @@ -31,7 +35,7 @@ impl Collector<String> for String {
}
}

impl Copy for Int {
impl Copy for String {
fn copy(self): Self {
copy(self)
}
Expand Down

0 comments on commit 50b3d7f

Please sign in to comment.