aboutsummaryrefslogtreecommitdiff
path: root/src/interp/compiler.boot
diff options
context:
space:
mode:
Diffstat (limited to 'src/interp/compiler.boot')
-rw-r--r--src/interp/compiler.boot134
1 files changed, 133 insertions, 1 deletions
diff --git a/src/interp/compiler.boot b/src/interp/compiler.boot
index 81860046..a297b448 100644
--- a/src/interp/compiler.boot
+++ b/src/interp/compiler.boot
@@ -1420,7 +1420,8 @@ compIs(["is",a,b],m,e) ==
-- One should always call the correct function, since the represent-
-- ation of basic objects may not be the same.
-coerce(T,m) ==
+tryCourtesyCoercion: (%Triple, %Mode) -> %Maybe %Triple
+tryCourtesyCoercion(T,m) ==
$InteractiveMode =>
keyedSystemError("S2GE0016",['"coerce",
'"function coerce called from the interpreter."])
@@ -1429,6 +1430,10 @@ coerce(T,m) ==
T':= coerceEasy(T,m) => T'
T':= coerceSubset(T,m) => T'
T':= coerceHard(T,m) => T'
+ nil
+
+coerce(T,m) ==
+ T' := tryCourtesyCoercion(T,m) => T'
-- if from from coerceable, this coerce was just a trial coercion
-- from compFormWithModemap to filter through the modemaps
T.expr = "$fromCoerceable$" or isSomeDomainVariable m => nil
@@ -1728,6 +1733,132 @@ compMapCond''(cexpr,dc) ==
compMapCondFun(fnexpr,op,dc,bindings) ==
[fnexpr,bindings]
+
+--% %Match
+
+
+++ Subroutine of compMatch, responsible of compiling individual alternative
+++ of the form
+++ x@t => stmt
+++ in environment `e'. Here `y' is the scrutinee, and `m' is the
+++ exit mode of `stmt'. And `T' is [y,m,e].
+++ Return a quadruple [code,mode,envTrue,envFalse], where
+++ code is a pair [cond, body]
+++ mode is the final mode (equal to m if everything is OK)
+++ envTrue is the environment resulting from compiling `stmt'
+++ envFalse is the environment for failed match.
+compRetractAlternative(x,t,stmt,m,s,T) ==
+ -- The retract pattern is compiled by transforming
+ -- x@t => sttmt
+ -- into the following program fragment
+ -- y case t => (x := <init>; stmt)
+ -- where <init> is code that compute appropriate initialization
+ -- for `x' under the condition that either `y' may be implicitly
+ -- convertible to t (using only courtesy coerciions) or that
+ -- `y' is retractable to t.
+ --
+ -- 1. Evaluate the retract condition.
+ y := T.expr -- guaranteed to be a name.
+ e := T.env
+ [caseCode,caseMode,e,envFalse] :=
+ compBoolean(["case",y,t],$Boolean,e) or return
+ stackAndThrow('"%1 is not retractable to %2",[s,t])
+ -- 2. Evaluate the actual retraction to `t'.
+ -- We try courtesy coercions first, then `retract'. That way
+ -- we can use optimized versions where available. That also
+ -- makes the scheme works for untagged unions.
+ [restrictCode,.,e] := tryCourtesyCoercion([y,T.mode,e],t) or
+ comp(["retract",y],t,e) or return nil
+ -- 3. Now declare `x'.
+ [.,.,e] := compMakeDeclaration([":",x,t],$EmptyMode,e) or return nil
+ e := put(x,"value",[genSomeVariable(),t,e],e)
+ -- 4. Compile body of the retract pattern.
+ stmtT := comp(stmt,m,e) or return
+ stackAndThrow('"could not compile %1b under mode %2pb",[stmt,m])
+ -- 5. Generate code for the whole pattern.
+ code := [caseCode, ["LET",[[x,restrictCode]],stmtT.expr]]
+ [code,stmtT.mode,stmtT.env,envFalse]
+
+
+++ Subroutine of compMatch, responsible for compiling alternative of
+++ of the form
+++ x: t => stmt
+++ in environment `e', where `y' is the scrutinee, and `m' is the
+++ exit mode of `stmt'. And `T' is [y,m,e].
+++ Return a quadruple [code,mode,envTrue,envFalse], where
+++ code is a pair [cond, body]
+++ mode is the final mode (equal to m if everything is OK)
+++ env is the environment resulting from compiling `stmt'
+compRecoverAlternative(x,t,stmt,m,s,T) ==
+ -- The retract pattern is compiled by transforming
+ -- x: t => sttmt
+ -- into the following program fragment
+ -- domainOf y is t => (x := <init>; stmt)
+ -- where <init> is code that compute appropriate initialization
+ -- for `x' under the condition that y if of type Any, and the
+ -- underlying type is t.
+ --
+ -- 1. Evaluate the recovery condition
+ y := T.expr -- guaranteed to be a name.
+ e := T.env
+ T.mode ^= $Any =>
+ stackAndThrow('"Scrutinee must be of type %b Any %d in type recovery alternative of case pattern",nil)
+ caseCode := ["EQUAL",["devaluate",t],["objMode",y]]
+ -- 2. Declare `x'.
+ [.,.,e] := compMakeDeclaration([":",x,t],$EmptyMode,e) or return nil
+ e := put(x,"value",[genSomeVariable(),t,e],e)
+ -- 3. Compile body of alternative
+ stmtT := comp(stmt,m,e) or return
+ stackAndThrow('"could not compile %1b under mode %2pb",[stmt,m])
+ -- 4. Assemble code
+ code := [caseCode,["LET",[[x,["objVal",y]]],stmtT.expr]]
+ [code,stmtT.mode,stmtT.env,e]
+
+warnUnreachableAlternative pat ==
+ stackWarning('"Alternative with pattern %1b will not be reached",[pat])
+
+warnTooManyOtherwise() ==
+ stackWarning('"One too many `otherwise' alternative",nil)
+
+compMatch(["%Match",subject,altBlock],m,e) ==
+ altBlock isnt ["%Block",:alts] =>
+ stackAndThrow('"case pattern must specify block of alternatives",nil)
+ savedEnv := e
+ -- 1. subjectTmp := subject
+ [se,sm,e] := comp(subject,$EmptyMode,e) or return nil
+ sn := GENSYM()
+ [.,.,e] := compMakeDeclaration([":",sn,sm],$EmptyMode,e)
+ or return nil
+ e := put(sn,"value",[genSomeVariable(),sm,e],e)
+ -- 2. compile alternatives.
+ altsCode := nil
+ catchAllCount := 0
+ for alt in alts repeat
+ alt is ["=>",pat,stmt] =>
+ pat is [op,x,t] and op in '(_: _@) =>
+ not IDENTP x =>
+ stackAndThrow('"pattern %1b must declare a variable",[pat])
+ if catchAllCount > 0 then
+ warnUnreachableAlternative pat
+ [code,mode,.,e] :=
+ op = ":" => compRecoverAlternative(x,t,stmt,m,subject,[sn,sm,e])
+ compRetractAlternative(x,t,stmt,m,subject,[sn,sm,e])
+ or return stackAndThrow('"cannot compile %1b",[alt])
+ altsCode := [code,:altsCode]
+ pat = "otherwise" =>
+ if catchAllCount > 0 then
+ warnTooManyOtherwise()
+ catchAllCount := catchAllCount + 1
+ [code,.,e] := comp(stmt,m,e) or return
+ stackAndThrow('"cannot compile",[stmt])
+ altsCode := [[true,code],:altsCode]
+ return stackAndThrow('"invalid pattern %1b",[pat])
+ return stackAndThrow('"invalid alternative %1b",[alt])
+ catchAllCount = 0 =>
+ stackAndThrow('"missing %b otherwise %d alternative in case pattern",nil)
+ code := ["LET",[[sn,se]],["COND",:nreverse altsCode]]
+ [code,m,savedEnv]
+
--% Register compilers for special forms.
-- Those compilers are on the `SPECIAL' property of the corresponding
-- special form operator symbol.
@@ -1772,5 +1903,6 @@ for x in [["|", :"compSuchthat"],_
["UnionCategory", :"compConstructorCategory"],_
["where", :"compWhere"],_
["%Comma",:"compComma"],_
+ ["%Match",:"compMatch"],_
["[||]", :"compileQuasiquote"]] repeat
MAKEPROP(first x, "SPECIAL", rest x)