UNPKG

@helios-lang/compiler

Version:

Helios is a Domain Specific Language that compiles to Plutus-Core (i.e. Cardano on-chain validator scripts). Helios is a non-Haskell alternative to Plutus. With this library you can compile Helios scripts and build Cardano transactions, all you need to bu

126 lines (106 loc) 3.61 kB
import { makeReferenceError, makeTypeError } from "@helios-lang/compiler-utils" import { $ } from "@helios-lang/ir" import { expectDefined as expectDefined } from "@helios-lang/type-utils" import { ToIRContext } from "../codegen/index.js" import { Scope } from "../scopes/index.js" import { Expr } from "./Expr.js" import { AllType, AnyType, DataEntity } from "../typecheck/common.js" /** * @import { Site, Word } from "@helios-lang/compiler-utils" * @import { SourceMappedStringI } from "@helios-lang/ir" * @import { TypeCheckContext } from "../index.js" * @typedef {import("../typecheck/index.js").EvalEntity} EvalEntity */ /** * ... . ... expression */ export class MemberExpr extends Expr { /** * @private * @readonly * @type {Expr} */ _objExpr /** * @private * @readonly * @type {Word} */ _memberName /** * @param {Site} site * @param {Expr} objExpr * @param {Word} memberName */ constructor(site, objExpr, memberName) { super(site) this._objExpr = objExpr this._memberName = memberName } /** * @param {TypeCheckContext} ctx * @param {Scope} scope * @returns {EvalEntity} */ evalInternal(ctx, scope) { const objVal_ = this._objExpr.eval(ctx, scope) let objVal = objVal_.asInstance if (!objVal) { ctx.errors.type(this._objExpr.site, `lhs of '.' not an instance`) objVal = new DataEntity(new AnyType()) } let member = objVal.instanceMembers[this._memberName.value] if (!member) { if (objVal?.type?.asEnumMemberType) { member = objVal.type.asEnumMemberType.parentType.instanceMembers[ this._memberName.value ] } if (!member) { ctx.errors.reference( this._memberName.site, `'${objVal.type.toString()}.${this._memberName.value}' undefined` ) member = new AllType() } } if (member.asParametric) { return member } else if (member.asType) { const memberVal = member.asType.toTyped() return memberVal } else { throw new Error("expected type or parametric") } } /** * @param {ToIRContext} ctx * @param {string} params - applied type parameters must be inserted Before the call to self * @returns {SourceMappedStringI} */ toIR(ctx, params = "") { // members can be functions so, field getters are also encoded as functions for consistency const objType = expectDefined( this._objExpr.cache?.asTyped?.type?.asNamed ) let objPath = objType.path // if we are getting the member of an enum member we should check if it a field or method, because for a method we have to use the parent type if ( objType.asEnumMemberType && objType.asEnumMemberType.instanceMembers[this._memberName.value] === undefined ) { objPath = objType.asEnumMemberType.parentType.path } const fullPath = `${objPath}__${this._memberName.toString()}${params}` let ir = $(fullPath, this._memberName.site) return $([ir, $("(", this.site), this._objExpr.toIR(ctx), $(")")]) } /** * @returns {string} */ toString() { return `${this._objExpr.toString()}.${this._memberName.toString()}` } }