Skip to content

Commit

Permalink
Ark: re-jig property access
Browse files Browse the repository at this point in the history
Rename ArkProperty to ArkField, and add ArkSetField, rather than using
ArkSet to set fields.

Similarly, rename ArkSetPropertyInst to ArkSetFieldInst, and remove
ArkSetInst, which is no longer required.
  • Loading branch information
rrthomas committed Aug 5, 2024
1 parent e9f18c3 commit 6e981d9
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 36 deletions.
8 changes: 7 additions & 1 deletion src/ark/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,18 @@ export class ArkObjectLiteral extends ArkExp {
}
}

export class ArkProperty extends ArkLvalue {
export class ArkField extends ArkLvalue {
constructor(public obj: ArkExp, public prop: string) {
super()
}
}

export class ArkSetField extends ArkExp {
constructor(public field: ArkField, public exp: ArkExp) {
super()
}
}

export class ArkListLiteral extends ArkExp {
constructor(public list: ArkExp[]) {
super()
Expand Down
6 changes: 3 additions & 3 deletions src/ark/compiler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
ArkLaunchBlockOpenInst, ArkLaunchBlockCloseInst, ArkLetBlockOpenInst,
ArkLocalInst, ArkCaptureInst, ArkListLiteralInst, ArkLiteralInst, ArkMapLiteralInst,
ArkObjectLiteralInst, ArkPropertyInst, ArkReturnInst, ArkYieldInst,
ArkSetInst, ArkSetPropertyInst,
ArkSetNamedLocInst, ArkSetFieldInst,
} from '../flatten.js'
import {
jsGlobals, ArkBoolean, ArkBooleanVal, ArkList, ArkMap, ArkNull,
Expand Down Expand Up @@ -191,14 +191,14 @@ export function flatToJs(insts: ArkInsts, file: string | null = null): CodeWithS
return sourceNode(letAssign(inst.id, `yield* ${inst.fnId.description}.body(${inst.argIds.map((id) => id.description).join(', ')})`))
} else if (inst instanceof ArkInvokeInst) {
return sourceNode(letAssign(inst.id, `yield* ${inst.objId.description}.get('${inst.prop}').body(${inst.argIds.map((id) => id.description).join(', ')})`))
} else if (inst instanceof ArkSetInst) {
} else if (inst instanceof ArkSetNamedLocInst) {
return sourceNode([
`if (${inst.lexpId.description} !== ArkUndefined && ${inst.lexpId.description}.constructor !== ArkNullVal && ${inst.valId.description}.constructor !== ${inst.lexpId.description}.constructor) {\n`,
'throw new JsRuntimeError(\'Assignment to different type\')\n',
'}\n',
letAssign(inst.id, `${inst.lexpId.description} = ${inst.valId.description}`),
])
} else if (inst instanceof ArkSetPropertyInst) {
} else if (inst instanceof ArkSetFieldInst) {
return sourceNode(letAssign(inst.id, `${inst.lexpId.description}.set('${inst.prop}', ${inst.valId.description})`))
} else if (inst instanceof ArkObjectLiteralInst) {
const objInits: string[] = []
Expand Down
35 changes: 15 additions & 20 deletions src/ark/flatten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ArkAnd, ArkAwait, ArkBreak, ArkCall, ArkCapture, ArkContinue, ArkDebugInfo,
ArkExp, ArkFn, ArkGenerator, ArkIf, ArkInvoke, ArkLaunch, ArkLet,
ArkListLiteral, ArkLiteral, ArkLocal, ArkLoop, ArkMapLiteral, ArkNamedLoc,
ArkObjectLiteral, ArkOr, ArkProperty, ArkReturn, ArkSequence, ArkSet, ArkYield,
ArkObjectLiteral, ArkOr, ArkField, ArkReturn, ArkSequence, ArkSet, ArkSetField, ArkYield,
} from './code.js'
import {ArkBoolean, ArkNull, ArkVal} from './data.js'

Expand Down Expand Up @@ -245,25 +245,20 @@ export class ArkInvokeInst extends ArkInst {
}
}

export class ArkSetInst extends ArkInst {
constructor(sourceLoc: Interval | undefined, public lexpId: symbol, public valId: symbol) {
super(sourceLoc)
}
}
export class ArkSetNamedLocInst extends ArkSetInst {
export class ArkSetNamedLocInst extends ArkInst {
constructor(
sourceLoc: Interval | undefined,
lexpId: symbol,
public lexpId: symbol,
public lexpIndex: number,
valId: symbol,
public valId: symbol,
) {
super(sourceLoc, lexpId, valId)
super(sourceLoc)
}
}
export class ArkSetLocalInst extends ArkSetNamedLocInst {}
export class ArkSetCaptureInst extends ArkSetNamedLocInst {}

export class ArkSetPropertyInst extends ArkInst {
export class ArkSetFieldInst extends ArkInst {
constructor(
sourceLoc: Interval | undefined,
public lexpId: symbol,
Expand Down Expand Up @@ -379,14 +374,6 @@ export function expToInsts(
])
} else if (exp instanceof ArkSet) {
const insts = expToInsts(exp.exp, innerLoop, innerFn)
if (exp.lexp instanceof ArkProperty) {
const objInsts = expToInsts(exp.lexp.obj, innerLoop, innerFn)
return new ArkInsts([
...objInsts.insts,
...insts.insts,
new ArkSetPropertyInst(exp.lexp.sourceLoc, objInsts.id, exp.lexp.prop, insts.id),
])
}
let SetInst
if (exp.lexp instanceof ArkLocal) {
SetInst = ArkSetLocalInst
Expand All @@ -399,6 +386,14 @@ export function expToInsts(
...insts.insts,
new SetInst(exp.sourceLoc, Symbol.for(exp.lexp.debug.name!), exp.lexp.index, insts.id),
])
} else if (exp instanceof ArkSetField) {
const insts = expToInsts(exp.exp, innerLoop, innerFn)
const objInsts = expToInsts(exp.field.obj, innerLoop, innerFn)
return new ArkInsts([
...objInsts.insts,
...insts.insts,
new ArkSetFieldInst(exp.field.sourceLoc, objInsts.id, exp.field.prop, insts.id),
])
} else if (exp instanceof ArkObjectLiteral) {
const insts: ArkInst[] = []
const valMap = new Map([...exp.properties.entries()].map(
Expand Down Expand Up @@ -476,7 +471,7 @@ export function expToInsts(
)
} else if (exp instanceof ArkLoop) {
return loopBlock(exp.sourceLoc, exp.localsDepth, exp.body, innerFn)
} else if (exp instanceof ArkProperty) {
} else if (exp instanceof ArkField) {
const objInsts = expToInsts(exp.obj, innerLoop, innerFn)
return new ArkInsts([
...objInsts.insts,
Expand Down
4 changes: 2 additions & 2 deletions src/ark/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
ArkLaunchBlockCloseInst, ArkLaunchBlockOpenInst, ArkLetBlockCloseInst, ArkLetBlockOpenInst,
ArkLetCopyInst, ArkListLiteralInst, ArkLiteralInst, ArkLocalInst, ArkLoopBlockCloseInst,
ArkLoopBlockOpenInst, ArkMapLiteralInst, ArkObjectLiteralInst, ArkPropertyInst, ArkReturnInst,
ArkSetCaptureInst, ArkSetLocalInst, ArkSetNamedLocInst, ArkSetPropertyInst, ArkYieldInst,
ArkSetCaptureInst, ArkSetLocalInst, ArkSetNamedLocInst, ArkSetFieldInst, ArkYieldInst,
} from './flatten.js'
import {
ArkAbstractObjectBase, ArkBoolean, ArkList, ArkMap, ArkNull, ArkNullVal,
Expand Down Expand Up @@ -331,7 +331,7 @@ function* doEvalFlat(outerArk: ArkState): Operation<ArkVal> {
mem.set(inst.id, result)
ref.set(result)
inst = inst.next
} else if (inst instanceof ArkSetPropertyInst) {
} else if (inst instanceof ArkSetFieldInst) {
const result = mem.get(inst.valId)!
const obj = mem.get(inst.lexpId)! as ArkObject
if (obj.get(inst.prop) === ArkUndefined) {
Expand Down
18 changes: 15 additions & 3 deletions src/ark/reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
ArkExp, ArkLvalue, ArkIf, ArkAnd, ArkOr, ArkSequence, ArkLoop, ArkBreak, ArkContinue,
ArkSet, ArkLocal, ArkCapture, ArkListLiteral, ArkObjectLiteral, ArkMapLiteral,
ArkFn, ArkGenerator, ArkReturn, ArkYield,
ArkProperty, ArkLet, ArkCall, ArkInvoke, ArkLiteral, ArkBoundVar, ArkNamedLoc,
ArkField, ArkLet, ArkCall, ArkInvoke, ArkLiteral, ArkBoundVar, ArkNamedLoc,
ArkSetField,
} from './code.js'
import {expToInst} from './flatten.js'
import {ArkState} from './interpreter.js'
Expand Down Expand Up @@ -142,7 +143,7 @@ export function symRef(env: Environment, name: string): ArkLvalue {
if (env.externalSyms.get(name) === ArkUndefined) {
throw new ArkCompilerError(`Undefined symbol ${name}`)
}
lexp = new ArkProperty(new ArkLiteral(env.externalSyms), name)
lexp = new ArkField(new ArkLiteral(env.externalSyms), name)
}
lexp.debug.name = name
lexp.debug.env = JSON.stringify(env)
Expand Down Expand Up @@ -200,7 +201,7 @@ function doCompile(env: Environment, value: unknown): ArkExp {
throw new ArkCompilerError("Invalid 'prop'")
}
const compiled = doCompile(env, value[2])
return new ArkProperty(compiled, value[1])
return new ArkField(compiled, value[1])
}
case 'set': {
if (value.length !== 3) {
Expand All @@ -216,6 +217,17 @@ function doCompile(env: Environment, value: unknown): ArkExp {
const compiledVal = doCompile(env, value[2])
return new ArkSet(compiledRef, compiledVal)
}
case 'set-field': {
if (value.length !== 4 || typeof value[2] !== 'string') {
throw new ArkCompilerError("Invalid 'set-field'")
}
const compiledRef = doCompile(env, value[1])
if (!(compiledRef instanceof ArkLvalue)) {
throw new ArkCompilerError('Invalid lvalue')
}
const compiledVal = doCompile(env, value[3])
return new ArkSetField(new ArkField(compiledRef, value[2]), compiledVal)
}
case 'list': {
const elems = listToVals(env, value.slice(1))
return new ArkListLiteral(elems)
Expand Down
9 changes: 5 additions & 4 deletions src/ark/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import {
ArkUndefined, NativeObject,
} from './data.js'
import {
ArkExp, ArkSequence,
ArkAnd, ArkOr, ArkIf, ArkLoop, ArkBreak, ArkContinue, ArkInvoke,
ArkSet, ArkLet, ArkCall, ArkFn, ArkGenerator, ArkReturn, ArkProperty,
ArkExp, ArkSequence, ArkAnd, ArkOr, ArkIf, ArkLoop, ArkBreak, ArkContinue, ArkInvoke,
ArkSet, ArkSetField, ArkLet, ArkCall, ArkFn, ArkGenerator, ArkReturn, ArkField,
ArkLiteral, ArkListLiteral, ArkMapLiteral, ArkObjectLiteral, ArkYield,
} from './code.js'

Expand Down Expand Up @@ -57,7 +56,9 @@ export function valToJs(val: ArkVal | ArkExp, externalSyms = globals) {
return ['invoke', doValToJs(val.obj), val.prop, ...val.args.map(doValToJs)]
} else if (val instanceof ArkSet) {
return ['set', doValToJs(val.lexp), doValToJs(val.exp)]
} else if (val instanceof ArkProperty) {
} else if (val instanceof ArkSetField) {
return ['set-field', doValToJs(val.field.obj), val.field.prop, doValToJs(val.exp)]
} else if (val instanceof ArkField) {
if (val.obj instanceof ArkLiteral && val.obj.val === externalSyms) {
// Serialize globals as simply their name.
return val.prop
Expand Down
10 changes: 7 additions & 3 deletions src/ursa/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import {
import {
ArkBoundVar, ArkExp, ArkLvalue, ArkLiteral, ArkSequence, ArkIf, ArkLoop, ArkAnd, ArkOr,
ArkObjectLiteral, ArkListLiteral, ArkMapLiteral,
ArkCall, ArkInvoke, ArkLet, ArkFn, ArkGenerator, ArkProperty, ArkSet, ArkReturn, ArkYield,
ArkCall, ArkInvoke, ArkLet, ArkFn, ArkGenerator, ArkField, ArkSet, ArkReturn, ArkYield,
ArkBreak, ArkContinue, ArkAwait, ArkLaunch, ArkCapture, ArkFnType, ArkNamedLoc,
ArkSetField,
} from '../ark/code.js'
import {ArkState, ArkRuntimeError} from '../ark/interpreter.js'
import {
Expand Down Expand Up @@ -140,7 +141,7 @@ function makeProperty(
object: ParserNonterminalNode,
property: ParserNode,
) {
return addLoc(new ArkProperty(object.toExp(a), property.sourceString), exp)
return addLoc(new ArkField(object.toExp(a), property.sourceString), exp)
}

function makeIfChain(ifs: ArkIf[]): ArkIf {
Expand Down Expand Up @@ -221,7 +222,7 @@ semantics.addOperation<LetBinding>('toLet(a)', {
// For path x.y.z, compile `let z = x.use("y", "z")`
const innerEnv = this.args.a.env.push([new Location(ident.sourceString, false)])
const libValue = path[0].toExp({...this.args.a, env: innerEnv})
const useProperty = addLoc(new ArkProperty(libValue, 'use'), this)
const useProperty = addLoc(new ArkField(libValue, 'use'), this)
const useCallArgs = path.slice(1).map((id) => new ArkLiteral(ArkString(id.sourceString)))
const useCall = addLoc(new ArkCall(useProperty, useCallArgs), this)
const index = this.args.a.env.top().locals.length
Expand Down Expand Up @@ -534,6 +535,9 @@ semantics.addOperation<ArkExp>('toExp(a)', {
if (compiledLvalue instanceof ArkNamedLoc && !compiledLvalue.isVar) {
throw new UrsaCompilerError(lvalue.source, "Cannot assign to non-'var'")
}
if (compiledLvalue instanceof ArkField) {
return addLoc(new ArkSetField(compiledLvalue, compiledValue), this)
}
return addLoc(new ArkSet(compiledLvalue, compiledValue), this)
},

Expand Down

0 comments on commit 6e981d9

Please sign in to comment.