# Copyright 2005-2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ Note: In the early days, ENodes were not as generic as they are now. Therefore, this file has some remnants of per-node tests for importing and making. --- Importing --- There is a special component loader supplying the ENode makers. ? def vm__uriGetter := # value: (However, this is just a regular package loader, and should be equivalent to the unabbreviated form.) ? # value: EExpr ? def makeLiteralExpr := # value: ? def makeNounExpr := # value: Type object accessibility: ? == .asType() # value: true Check that the special loaders handle the nonexistent cases: ? # problem: can't find "org.erights.e.elang.evm.makeNoSuchNode" ? # no maker # problem: can't find "org.erights.e.elang.evm.makeENode" --- Properties, unrecognized methods, and type information --- ? makeNounExpr(null, "foo", null).getName() # value: "foo" ? makeNounExpr(null, "foo", null).getNonexistentProperty() # problem: no such method: org.erights.e.elang.evm.NounExpr#getNonexistentProperty/0 ? makeNounExpr(null, "foo", null).get() # problem: no such method: org.erights.e.elang.evm.NounExpr#get/0 ? makeNounExpr(null, "foo", null).getName("extraArg") # problem: no such method: org.erights.e.elang.evm.NounExpr#getName/1 ? makeNounExpr(null, "foo", null).unrecognizedMethod() # problem: no such method: org.erights.e.elang.evm.NounExpr#unrecognizedMethod/0 ? makeNounExpr(null, "foo", null).__respondsTo("getName", 0) # value: true ? makeNounExpr(null, "foo", null).__respondsTo("getName", 1) # value: false ? makeNounExpr(null, "foo", null).__respondsTo("getNonexistentProperty", 0) # value: false ? makeNounExpr(null, "foo", null).__respondsTo("get", 0) # value: false ? makeNounExpr(null, "foo", null).__respondsTo("unrecognizedMethod", 0) # value: false XXX this is just testing what currently happens; it *should* contain message descs for the properties (and better doc comments, too) ? help(makeNounExpr(null, "foo", null)) # value: interface "org.erights.e.elang.evm.NounExpr" { # to asText(_) # /** e */ # to quasiTypeTag() # /** Return a static scope analysis of this subtree that doesn't depend on the enclosing context. */ # to staticScope() # to getOptSpan() # /** Quasiliteral ValueMaker interface. # # NOTE: There is a non-transparent optimization, with the effect that if args == [] and there are quasi-nodes in this tree, they will be returned unreplaced. */ # to substitute(args :ConstList) # to asKernelE() # to welcome(visitor) # /** Traverse the scope structure of this node. See the org.erights.e.elang.evm.StaticWalkEnvironment interface. */ # to walkScopes(environment) # /** Java-E compatibility */ # to lnPrintOn(tw, precedence) # /** Java-E compatibility */ # to subPrintOn(tw, precedence) # to requireKernelE(_) # to requireFitsScope(_, _) # to eval(scope) # /** Evaluate this expression in the given outer scope and return a tuple of the return value and a scope containing any new bindings. */ # to evalToPair(scope) # } --- SourceSpans --- ? def makeSourceSpan := # value: ? def node := makeNounExpr(makeSourceSpan("data:text/plain,foo", true, 1, 0, 1, 2), "foo", null) # value: e`foo` ? node.getOptSpan() # value: --- Makers --- Call patterns ? pragma.enable("call-pattern") ? def makeNounExpr(a, b, c) := node # value: e`foo` ? [a, b, c] # value: [, "foo", null] ? def makeNounExpr(_, _, _) := "foo" # problem: the String "foo" doesn't coerce to a NounExpr --- Selflessness of nodes --- ? makeNounExpr(null, "aardvark", null).__optUncall() # value: [, "run", [null, "aardvark", null]] ? Ref.isPassByCopy(makeNounExpr(null, "aardvark", null)) # value: true --- staticScope as object --- ? def makeStaticScope := # value: ? def makeFinalPattern := # value: ? def makeVarPattern := # value: ? def makeBindingPattern := # value: empty scope ? def empty := makeStaticScope.getEmptyScope() # value: <[] := [] =~ [] + var []> scopeDef ? def sdef1 := makeStaticScope.scopeDef(makeFinalPattern(null, makeNounExpr(null, "x", null), null, null)) # value: <[] := [] =~ ["x"] + var []> ? def sdef2 := makeStaticScope.scopeDef(makeFinalPattern(null, makeNounExpr(null, "y", null), null, null)) # value: <[] := [] =~ ["y"] + var []> ? sdef1.defNames() # value: ["x" => epatt`x`] scopeRead / namesRead ? def readAny := makeStaticScope.scopeRead(makeNounExpr(null, "any", null)) # value: <[] := ["any"] =~ [] + var []> ? readAny.namesRead() # value: ["any" => e`any`] scopeAssign / namesSet ? def setPi := makeStaticScope.scopeAssign(makeNounExpr(null, "pi", null)) # value: <["pi"] := [] =~ [] + var []> ? setPi.namesSet() # value: ["pi" => e`pi`] namesUsed ? readAny + setPi # value: <["pi"] := ["any"] =~ [] + var []> ? (readAny + setPi).namesUsed() # value: ["pi" => e`pi`, "any" => e`any`] scopeVar / varNames / scopeSlot ? def varI := makeStaticScope.scopeVar(makeVarPattern(null, makeNounExpr(null, "i", null), null, null)) # value: <[] := [] =~ [] + var ["i"]> ? makeStaticScope.scopeBinding(makeBindingPattern(null, makeNounExpr(null, "i", null), null)) # value: <[] := [] =~ [] + var ["i"]> ? varI.varNames() # value: ["i" => epatt`var i`] outNames ? (sdef1 + sdef2 + varI).outNames() # value: ["i" => epatt`var i`, "y" => epatt`y`, "x" => epatt`x`] scopeMeta ? def scopeMetaState := makeStaticScope.scopeMeta() # value: <[] := [] =~ [] + var [], meta.getState()> ? empty.hasMetaStateExpr() # value: false ? scopeMetaState.hasMetaStateExpr() # value: true concatenation ? empty + empty # value: <[] := [] =~ [] + var []> ? sdef1 + def _ { to __conformTo(_) :any { return empty }} # problem: no such method: __main$_#defNames/0 x # value: <[] := [] =~ ["x"] + var []> ? sdef1 + sdef2 # value: <[] := [] =~ ["y", "x"] + var []> left defs hide right reads ? sdef1 + makeNounExpr(null, "x", null).staticScope() # value: <[] := [] =~ ["x"] + var []> left vars hide right reads ? varI + makeNounExpr(null, "i", null).staticScope() # value: <[] := [] =~ [] + var ["i"]> left vars hide right sets ? varI + makeStaticScope.scopeAssign(makeNounExpr(null, "i", null)) # value: <[] := [] =~ [] + var ["i"]> left defs hide right vars, even though this is an invalid expression ? sdef1 + makeStaticScope.scopeAssign(makeNounExpr(null, "x", null)) # value: <[] := [] =~ ["x"] + var []> meta.getState() is contagious ? empty + makeStaticScope.scopeMeta() # value: <[] := [] =~ [] + var [], meta.getState()> ? makeStaticScope.scopeMeta() + empty # value: <[] := [] =~ [] + var [], meta.getState()> hide ? (sdef1 + sdef2 + varI).hide() # value: <[] := [] =~ [] + var []> ? (readAny + setPi).hide() # value: <["pi"] := ["any"] =~ [] + var []> ? makeStaticScope.scopeMeta().hide() # value: <[] := [] =~ [] + var [], meta.getState()> uses ? makeStaticScope.scopeMeta()."uses"("x") # value: true ? empty."uses"("x") # value: false ? readAny."uses"("any") # value: true ? readAny."uses"("x") # value: false ? setPi."uses"("pi") # value: true ? sdef1."uses"("x") # value: false ? varI."uses"("i") # value: false constructor for selflessness ? def complexScope := (readAny + setPi + sdef1 + varI) # value: <["pi"] := ["any"] =~ ["x"] + var ["i"]> ? complexScope == E.call(E, "call", complexScope.__optUncall()) # value: true --- Evaluation --- Here we test the explicit evaluation messages. See vm.updoc for testing of every node's behavior. eval ? e`1 + 1`.eval(safeScope) # value: 2 ? e`def f(x) :any {print(x); return x + 1}`.eval(privilegedScope)(44) # stdout: 44 # value: 45 evalToPair ? safeScope # value: ? def [_, newScope] := e`def x := "leftward"`.evalToPair(safeScope) # value: ["leftward", ] ? e`x`.evalToPair(safeScope) # problem: undefined variable: x ? e`x`.eval(newScope) # value: "leftward" Binding guard preservation ? def [_, newScope] := e` > def x :String := "" > def &y :(def g extends any {}) := &x > `.evalToPair(safeScope) > newScope.bindings().fetch("x", throw).getGuard() # value: FinalSlot[String] XXX bindings facet should provide get/1 ? newScope.bindings().fetch("y", throw).getGuard() # value: ? e`escape r { > def _ implements (def _ { > to audit(a) { r([a.getGuard("x"), a.getGuard("y")]) }} > ) { > to f() { x;y } > } > }`.eval(newScope) # value: [FinalSlot[String], ] --- Printing --- Bug test: nested code was not being printed with the indenting TextWriter, resulting in only the first line being indented ? e`{x; y}` # value: e`{ # x # y # }` Special printing methods ? e`a := b`.subPrintOn(stdout, 0) # stdout: (a := b) ? e`a := b`.subPrintOn(stdout, 100) # stdout: a := b ? e`a := b`.lnPrintOn(stdout, 0) # stdout: # (a := b) ? e`a := b`.lnPrintOn(stdout, 100) # stdout: # a := b XXX these are compatibility methods; decide whether to keep them. --- Quasi-substitution --- XXX replace this makeVisitor (which now exists here and in kernel.updoc) with org.cubik.cle.dumpENodes ? def makeVisitor(depth) :any { > return def spamVisitor { > match [`visit@name`, [optOriginal] + elements] { > println(`${" " * depth}$name ${E.toQuote(optOriginal).split("\n")[0]}...`) > for element in elements { > if (element.__respondsTo("welcome", 1)) { element.welcome(makeVisitor(depth + 1)) > } else if (element =~ l :List ? (l !~ s :String)) { E.call(makeVisitor(depth + 1), "visit_list", [null] + l) > } else { > println(`${" " * (depth + 1)}$element`) > } > } > } > } > } # value: ? (null, (null, 0, null), null).welcome(makeVisitor(0)) # stdout: HideExpr e`{... # QuasiLiteralExpr e`${0}`... # 0 # ? (null, (null, 0, null), null).substitute([(null, "foo", null)]).welcome(makeVisitor(0)) # stdout: HideExpr e`{... # LiteralExpr e`"foo"`... # foo # --- Serialization --- ? def st :PassByCopy := makeNounExpr(null, "foo", null) # value: e`foo` ? def u := st.__optUncall() # value: [, "run", [null, "foo", null]] ? u[0] == makeNounExpr # value: true ? makeNounExpr :StandardGraphExit # problem: the "org.erights.e.elang.evm.makeNounExpr" doesn't coerce to a ? makeNounExpr :PassByCopy # value: XXX should be an uncall by , not miranda message ? makeNounExpr.__optUncall() # value: [, "get", ["org.erights.e.elang.evm.makeNounExpr"]] ? st :Data # value: e`foo` XXX maker tests for nodes that don't have them yet ' -- many makers have been indirectly tested by the current implementation of KernelECopyVisitor, but we should have proper tests including coercion checks XXX SourceSpan preservation XXX eval/evalToPair must have ejector arguments to distinguish compile errors from eval errors XXX semirandom node builder/tester? use for: confirm that all nodes print parseably no unexpected classes of errors (nodebuilder/compiler/generated code choking)