From 5977f71c81ae4f5e05b5aa5c9da73d779da8cc57 Mon Sep 17 00:00:00 2001 From: Patrick Li Date: Sat, 15 Oct 2022 23:28:26 -0700 Subject: [PATCH] Add more timing log sections. --- compiler/dependencies.stanza | 49 ++++++++++++++++++++--- compiler/el-to-vm.stanza | 76 ++++++++++++++++++++---------------- compiler/input.stanza | 27 ++++++++++--- compiler/main.stanza | 44 +++++++++++---------- compiler/params.stanza | 2 +- compiler/renamer.stanza | 24 ++++++++---- compiler/repl.stanza | 40 ++++++++++--------- compiler/tl-to-el.stanza | 37 ++++++++++++------ compiler/type.stanza | 20 ++++++++-- compiler/vm-analyze.stanza | 30 ++++++++------ compiler/vm-normalize.stanza | 22 +++++++---- compiler/vm.stanza | 22 +++++++---- core/core.stanza | 35 ++++++++--------- 13 files changed, 275 insertions(+), 153 deletions(-) diff --git a/compiler/dependencies.stanza b/compiler/dependencies.stanza index 10d41f248..e504f90c1 100644 --- a/compiler/dependencies.stanza +++ b/compiler/dependencies.stanza @@ -32,8 +32,8 @@ public defn analyze-dependencies (settings:BuildSettings, for e in errors(dep-result) do : println(o, Indented(e)) - match(output:String) : spit(output, LineWrapped(text)) - else : println(LineWrapped(text)) + match(output:String) : spit(output, text) + else : println(text) ;Output to graphviz match(graphviz:String) : @@ -77,33 +77,70 @@ public defn analyze-dependencies (settings:BuildSettings, driver() ;============================================================ -;======================= Datastructures ===================== +;============== Dependencies for Each Package =============== ;============================================================ defstruct Dependencies : package-dependencies: Tuple>> component-dependencies: Tuple,List>> +with: + constructor => #Dependencies + +defn Dependencies ( + package-dependencies: Tuple>> + component-dependencies: Tuple,List>>) : + + defn sort-values (xs:Seqable>>) : + for e in xs seq : key(e) => to-list(lazy-qsort(value(e))) + + defn sort-keys (xs:Seqable, ?V>>) : + for e in xs seq : to-list(lazy-qsort(key(e))) => value(e) + + val sorted-package-dependencies = + package-dependencies $> sort-values + $> qsort{key, _} + + val sorted-component-dependencies = + component-dependencies $> sort-values + $> sort-keys + $> qsort{head{key(_)}, _} + + #Dependencies(sorted-package-dependencies, + sorted-component-dependencies) + defmethod print (o:OutputStream, d:Dependencies) : defn empty-paren? (xs:Tuple) : " ()" when empty?(xs) else "" + + defn line-wrapped-list (xs:List) : + if empty?(xs) : + "()" + else : + val wrapped = LineWrapped("%@" % [xs]) + "(\n%_)" % [Indented(wrapped)] print(o, "Package Dependencies:%_" % [empty-paren?(package-dependencies(d))]) val import-list = for entry in package-dependencies(d) seq : - "\n%~ imports %~" % [key(entry), value(entry)] + "\n%~ imports %_" % [key(entry), line-wrapped-list(value(entry))] print(o, Indented("%*" % [import-list])) lnprint(o, "Package Group Dependencies:%_" % [empty-paren?(component-dependencies(d))]) val component-list = for entry in component-dependencies(d) seq : - "\n%~ imports %~" % [key(entry), value(entry)] + "\n%~ imports %_" % [key(entry), line-wrapped-list(value(entry))] print(o, Indented("%*" % [component-list])) +;============================================================ +;================ Location of Source Files ================== +;============================================================ + defstruct SourceFiles : entries: Tuple> with: constructor => #SourceFiles defn SourceFiles (entries:Seqable>) : - #SourceFiles(to-tuple(entries)) + val sorted-entries = qsort(key, entries) + #SourceFiles(sorted-entries) defmethod print (o:OutputStream, sf:SourceFiles) : defn empty-paren? (xs:Tuple) : " ()" when empty?(xs) else "" diff --git a/compiler/el-to-vm.stanza b/compiler/el-to-vm.stanza index 6894705af..6014a210e 100644 --- a/compiler/el-to-vm.stanza +++ b/compiler/el-to-vm.stanza @@ -13,46 +13,54 @@ defpackage stz/el-to-vm : import stz/algorithms import stz/ehier import core/stack-trace + import stz/timing-log-api + +;============================================================ +;====================== Timers ============================== +;============================================================ + +val EL-TO-VM = TimerLabel("EL-IR to VM-IR") ;============================================================ ;======================== Driver ============================ ;============================================================ public defn compile (epackage:EPackage) -> VMPackage : - val io = packageio(epackage) - val iotable = IOTable(io) - val ehier = EHier(epackage) - val progbuffer = ProgBuffer() - val global-table = GlobalTable(io, epackage) - val init-compiler = Compiler(global-table, iotable, ehier, progbuffer) - take-ids(cat(used-ids(io), used-ids(epackage))) - val dtable = within time-ms!("Analyze Dependencies") : - analyze-dependencies(epackage, global-table) - - compile-debug-info(progbuffer, io) - val init = within time-ms!("Compile to VM") : - for e in exps(epackage) do : - match(e) : - (e:EDefn) : compile(e, global-table, iotable, ehier, progbuffer) - (e:EDefClosure) : compile(e, dtable, global-table, iotable, ehier, progbuffer) - (e:EDefGlobal) : compile(e, global-table, progbuffer) - (e:EDefStruct) : compile(e, global-table, iotable, progbuffer) - (e:EInit) : compile(init-compiler, e) - (e:EExtern) : compile(e, progbuffer) - (e:EDefType) : compile(e, progbuffer) - (e:EDefObject) : compile(e, dtable, global-table, iotable, progbuffer) - (e:EDefTypeObject) : compile(e, global-table, iotable, ehier, progbuffer) - (e:EDefmulti) : compile(e, global-table, iotable, ehier, progbuffer) - (e:EDefmethod) : compile(e, global-table, iotable, ehier, progbuffer) - (e:EExternFn) : compile(e, global-table, iotable, ehier, progbuffer) - val init = compile-init(init-compiler, iotable, progbuffer) - init - - val vmp = to-vmpackage(progbuffer, io, init) - ;dump(vmp, "logs", "pre-analyze") - val vmp* = within time-ms!("VM Analyze") : analyze(vmp) - ;dump(vmp*, "logs", false) - vmp* + within log-time(EL-TO-VM, suffix(name(epackage))) : + val io = packageio(epackage) + val iotable = IOTable(io) + val ehier = EHier(epackage) + val progbuffer = ProgBuffer() + val global-table = GlobalTable(io, epackage) + val init-compiler = Compiler(global-table, iotable, ehier, progbuffer) + take-ids(cat(used-ids(io), used-ids(epackage))) + val dtable = within time-ms!("Analyze Dependencies") : + analyze-dependencies(epackage, global-table) + + compile-debug-info(progbuffer, io) + val init = within time-ms!("Compile to VM") : + for e in exps(epackage) do : + match(e) : + (e:EDefn) : compile(e, global-table, iotable, ehier, progbuffer) + (e:EDefClosure) : compile(e, dtable, global-table, iotable, ehier, progbuffer) + (e:EDefGlobal) : compile(e, global-table, progbuffer) + (e:EDefStruct) : compile(e, global-table, iotable, progbuffer) + (e:EInit) : compile(init-compiler, e) + (e:EExtern) : compile(e, progbuffer) + (e:EDefType) : compile(e, progbuffer) + (e:EDefObject) : compile(e, dtable, global-table, iotable, progbuffer) + (e:EDefTypeObject) : compile(e, global-table, iotable, ehier, progbuffer) + (e:EDefmulti) : compile(e, global-table, iotable, ehier, progbuffer) + (e:EDefmethod) : compile(e, global-table, iotable, ehier, progbuffer) + (e:EExternFn) : compile(e, global-table, iotable, ehier, progbuffer) + val init = compile-init(init-compiler, iotable, progbuffer) + init + + val vmp = to-vmpackage(progbuffer, io, init) + ;dump(vmp, "logs", "pre-analyze") + val vmp* = within time-ms!("VM Analyze") : analyze(vmp) + ;dump(vmp*, "logs", false) + vmp* ;============================================================ ;====================== Unique IDs ========================== diff --git a/compiler/input.stanza b/compiler/input.stanza index 8fb031ca2..4fc3eb1fb 100644 --- a/compiler/input.stanza +++ b/compiler/input.stanza @@ -6,20 +6,35 @@ defpackage stz/input : import stz/il-ir import stz/dl-ir import stz/visibility + import stz/timing-log-api + +;============================================================ +;======================= Timers ============================= +;============================================================ + +val IL-IR = TimerLabel("IL-IR") +val READ-TO-IL = TimerLabel(IL-IR, suffix("Read to IL")) +val CHECK-IL = TimerLabel(IL-IR, suffix("Check IL")) ;============================================================ ;======================== Driver ============================ ;============================================================ public defn to-ipackages (form, default-imports:Tuple) -> Tuple : - val e = read-iexp(form) - check(e) - split-packages(e, default-imports) + within log-time(IL-IR) : + val e = within log-time(READ-TO-IL) : + read-iexp(form) + within log-time(CHECK-IL) : + check(e) + split-packages(e, default-imports) public defn to-il (form) -> IExp : - val e = read-iexp(form) - check(e) - e + within log-time(IL-IR) : + val e = within log-time(READ-TO-IL) : + read-iexp(form) + within log-time(CHECK-IL) : + check(e) + e ;============================================================ ;========== Exported Types from IPackage ==================== diff --git a/compiler/main.stanza b/compiler/main.stanza index 4f08da959..9539997c2 100644 --- a/compiler/main.stanza +++ b/compiler/main.stanza @@ -549,6 +549,7 @@ defn repl-command () : Flag("terminal-style", OneFlag, OptionalFlag, "The terminal style (simple/edit) to use for the REPL. If not provided, defaults to 'edit' if available \ on the current platform.") + common-stanza-flag("timing-log") Flag("-", AllRemainingFlag, OptionalFlag, "If provided, the remaining arguments after this flag will be set as the command line arguments for the REPL session.")] @@ -568,33 +569,34 @@ defn repl-command () : ;Main code. Will potentially be wrapped in a finally clause ;if -confirm-before-exit is provided. defn main () : - ;Read configuration file - read-config-file() + within run-with-timing-log(cmd-args) : + ;Read configuration file + read-config-file() - ;Add pkg directories to pkg-dirs - for dir in get?(cmd-args, "pkg", []) do : - STANZA-PKG-DIRS = cons(dir, STANZA-PKG-DIRS) + ;Add pkg directories to pkg-dirs + for dir in get?(cmd-args, "pkg", []) do : + STANZA-PKG-DIRS = cons(dir, STANZA-PKG-DIRS) - ;Add flags - for flag in get?(cmd-args, "flags", []) do : - add-flag(to-symbol(flag)) + ;Add flags + for flag in get?(cmd-args, "flags", []) do : + add-flag(to-symbol(flag)) - ;Add platform flag - add-flag(platform-flag(OUTPUT-PLATFORM)) + ;Add platform flag + add-flag(platform-flag(OUTPUT-PLATFORM)) - ;Setup command line arguments. - val new-cmd-args = to-tuple $ cat(["repl"], get?(cmd-args, "-", [])) - set-command-line-arguments(new-cmd-args) + ;Setup command line arguments. + val new-cmd-args = to-tuple $ cat(["repl"], get?(cmd-args, "-", [])) + set-command-line-arguments(new-cmd-args) - ;Get the desired terminal style. - val terminal-style = - if flag?(cmd-args, "terminal-style") : - parse-terminal-style(cmd-args["terminal-style"]) as TerminalStyle - else : - default-terminal-style() + ;Get the desired terminal style. + val terminal-style = + if flag?(cmd-args, "terminal-style") : + parse-terminal-style(cmd-args["terminal-style"]) as TerminalStyle + else : + default-terminal-style() - ;Launch REPL - repl(args(cmd-args), terminal-style) + ;Launch REPL + repl(args(cmd-args), terminal-style) ;Confirm exit if flag?(cmd-args, "confirm-before-exit") : diff --git a/compiler/params.stanza b/compiler/params.stanza index 0b2ac60a3..7129ab9ca 100644 --- a/compiler/params.stanza +++ b/compiler/params.stanza @@ -15,7 +15,7 @@ public defn compiler-flags () : to-tuple(COMPILE-FLAGS) ;========= Stanza Configuration ======== -public val STANZA-VERSION = [0 17 28] +public val STANZA-VERSION = [0 17 29] public var STANZA-INSTALL-DIR:String = "" public var OUTPUT-PLATFORM:Symbol = `platform public var STANZA-PKG-DIRS:List = List() diff --git a/compiler/renamer.stanza b/compiler/renamer.stanza index f4031ab72..f00b52e85 100644 --- a/compiler/renamer.stanza +++ b/compiler/renamer.stanza @@ -9,6 +9,13 @@ defpackage stz/renamer : import stz/utils import stz/dl-ir import stz/visibility + import stz/timing-log-api + +;============================================================ +;===================== Timers =============================== +;============================================================ + +val IL-RENAMER = TimerLabel("IL Rename") ;============================================================ ;===================== Rename =============================== @@ -24,14 +31,15 @@ public defn rename-il (ipackages:Tuple) -> RenameResult : ;Rename all packages ipackages* = to-tuple $ for ipackage in ipackages* seq? : - val eng = Engine(name(ipackage)) - val exps* = map(rename-exp{_, eng}, exps(ipackage)) - if empty?(/errors(eng)) : - val ipackage* = sub-namemap(sub-exps(ipackage, exps*), namemap(eng)) - One(ipackage*) - else : - add-all(errors, /errors(eng)) - None() + within log-time(IL-RENAMER, suffix(name(ipackage))) : + val eng = Engine(name(ipackage)) + val exps* = map(rename-exp{_, eng}, exps(ipackage)) + if empty?(/errors(eng)) : + val ipackage* = sub-namemap(sub-exps(ipackage, exps*), namemap(eng)) + One(ipackage*) + else : + add-all(errors, /errors(eng)) + None() ;Return result val error = RenameErrors(to-tuple(errors)) when not empty?(errors) diff --git a/compiler/repl.stanza b/compiler/repl.stanza index 73ff6c6eb..e216c4bf7 100644 --- a/compiler/repl.stanza +++ b/compiler/repl.stanza @@ -50,6 +50,7 @@ val REPL-EXP-EVALUATION = TimerLabel("Repl Exp Evaluation") val REPL-COMPILE-LOWERED = TimerLabel("Repl Compile Lowered", REPL-LOWERING-AND-COMPILATION) val REPL-LOAD-INTO-VM = TimerLabel("Repl Load Into Vm", REPL-EXP-EVALUATION) val REPL-INIT-PACKAGES = TimerLabel("Repl Init Packages", REPL-EXP-EVALUATION) +val REPL-RELOAD = TimerLabel("Repl Reload") ;============================================================ ;===================== REPL Language ======================== @@ -355,25 +356,26 @@ public defn REPL () : ;Reload defn reload-files () : - within intercept-errors() : - val inputs = changed-files(file-env) - val vmpackages = compile-to-vmpackages(inputs, {[]}, false) - load(vm, vmpackages, false) - - ;Clear all globals - clear-globals(vm) - - ;Clear all REPL definitions - val r = unload(denv, repl-packages(repl-env), []) - fatal("Could not unload repl definitions.") when r is LoadErrors - unload(vm, repl-packages(repl-env)) - clear(repl-env) - - ;Rerun package initializers - init-packages(ordered-pkg-names) where : - val pkg-names = to-tuple $ seq(package,packageios(denv)) - val dependency-graph = package-dependency-graph(denv) - val ordered-pkg-names = initialization-order(dependency-graph, pkg-names) + within log-time(REPL-RELOAD) : + within intercept-errors() : + val inputs = changed-files(file-env) + val vmpackages = compile-to-vmpackages(inputs, {[]}, false) + load(vm, vmpackages, false) + + ;Clear all globals + clear-globals(vm) + + ;Clear all REPL definitions + val r = unload(denv, repl-packages(repl-env), []) + fatal("Could not unload repl definitions.") when r is LoadErrors + unload(vm, repl-packages(repl-env)) + clear(repl-env) + + ;Rerun package initializers + init-packages(ordered-pkg-names) where : + val pkg-names = to-tuple $ seq(package,packageios(denv)) + val dependency-graph = package-dependency-graph(denv) + val ordered-pkg-names = initialization-order(dependency-graph, pkg-names) ;Load from repl defn load-repl (form) : diff --git a/compiler/tl-to-el.stanza b/compiler/tl-to-el.stanza index 89228781d..22bb7e757 100644 --- a/compiler/tl-to-el.stanza +++ b/compiler/tl-to-el.stanza @@ -13,20 +13,33 @@ defpackage stz/tl-to-el : import stz/namemap with : prefix(EType) => NM import stz/algorithms + import stz/timing-log-api + +;============================================================ +;====================== Timers ============================== +;============================================================ + +val TL-TO-EL = TimerLabel("TL to EL") + +;============================================================ +;==================== Main Driver =========================== +;============================================================ public defn to-el (p:TProg, transient-package?:True|False) -> Tuple : - ;Find all exports in program - val export-table = ExportTable(p) - - ;Construct id-environment - val id-env = new IDEnv : - defmethod get (this, id:RecId) : export-table[id] - within set-id-env(id-env) : - val struct-table = StructTable(packages(p), environment(p)) - to-tuple $ for package in packages(p) seq : - val compiled = compile(package, struct-table, namemap(p)) - val io = analyze-imports(compiled, export-table, transient-package?) - sub-packageio(compiled, io) + within log-time(TL-TO-EL) : + ;Find all exports in program + val export-table = ExportTable(p) + + ;Construct id-environment + val id-env = new IDEnv : + defmethod get (this, id:RecId) : export-table[id] + within set-id-env(id-env) : + val struct-table = StructTable(packages(p), environment(p)) + to-tuple $ for package in packages(p) seq : + within log-time(TL-TO-EL, suffix(name(package))) : + val compiled = compile(package, struct-table, namemap(p)) + val io = analyze-imports(compiled, export-table, transient-package?) + sub-packageio(compiled, io) defn compile (p:TPackage, struct-table:StructTable, namemap:NameMap) : val texps = Vector() diff --git a/compiler/type.stanza b/compiler/type.stanza index e349dccfc..fdbf45590 100644 --- a/compiler/type.stanza +++ b/compiler/type.stanza @@ -14,6 +14,16 @@ defpackage stz/type : import stz/ids import stz/primitives import stz/tl-to-dl + import stz/timing-log-api + +;============================================================ +;====================== Timers ============================== +;============================================================ + +val TYPE-IR = TimerLabel("TL-IR") +val IL-TO-TL = TimerLabel(TYPE-IR, suffix("IL-IR to TL-IR")) +val INFER-TYPES = TimerLabel(TYPE-IR, suffix("Infer Types")) +val CHECK-ERRORS = TimerLabel(TYPE-IR, suffix("Check Errors")) ;============================================================ ;====================== Driver ============================== @@ -35,12 +45,16 @@ public defn type-program (ipackages:Tuple, environment:Env) -> TProg|T else : None() val id-env = new IDEnv : defmethod get (this, id:TypeId) : id-table[id] + within set-id-env(id-env) : try : - val [prog, hier] = to-tprog(ipackages, nm, exports) + val [prog, hier] = within log-time(IL-TO-TL) : + to-tprog(ipackages, nm, exports) set-current-hierarchy(hier) - val [prog*, env, ls-env] = infer-types(prog) - report-errors(nm, prog*, env, ls-env) + val [prog*, env, ls-env] = within log-time(INFER-TYPES) : + infer-types(prog) + within log-time(CHECK-ERRORS) : + report-errors(nm, prog*, env, ls-env) compute-packageios(prog*, nm) catch (e:TypeErrors) : e diff --git a/compiler/vm-analyze.stanza b/compiler/vm-analyze.stanza index 25c2f610a..380e472cc 100644 --- a/compiler/vm-analyze.stanza +++ b/compiler/vm-analyze.stanza @@ -4,23 +4,31 @@ defpackage stz/vm-analyze : import stz/vm-ir import stz/basic-ops import stz/utils + import stz/timing-log-api + +;============================================================ +;======================= Timers ============================= +;============================================================ + +val VM-ANALYSIS = TimerLabel("VM Slot Analysis") ;============================================================ ;====================== Driver ============================== ;============================================================ public defn analyze (vmp:VMPackage) : - val funcs* = for f in funcs(vmp) map : - val func* = match(func(f)) : - (func:VMMultifn) : - val funcs* = for f in funcs(func) map : - key(f) => analyze(value(f)) - val default* = analyze(default(func)) - VMMultifn(arg(func), funcs*, default*) - (func:VMFunc) : - analyze(func) - sub-func(f, func*) - sub-funcs(vmp, funcs*) + within log-time(VM-ANALYSIS, suffix(name(vmp))) : + val funcs* = for f in funcs(vmp) map : + val func* = match(func(f)) : + (func:VMMultifn) : + val funcs* = for f in funcs(func) map : + key(f) => analyze(value(f)) + val default* = analyze(default(func)) + VMMultifn(arg(func), funcs*, default*) + (func:VMFunc) : + analyze(func) + sub-func(f, func*) + sub-funcs(vmp, funcs*) ;============================================================ ;================== Post-Order Algorithm ==================== diff --git a/compiler/vm-normalize.stanza b/compiler/vm-normalize.stanza index 42d1ce558..ea2a73f58 100644 --- a/compiler/vm-normalize.stanza +++ b/compiler/vm-normalize.stanza @@ -8,6 +8,7 @@ defpackage stz/vm-normalize : import stz/call-records with: prefix(StdArg, ShadowArg, ArgType, CallLoc, CallRecord) => Stz import core/stack-trace + import stz/timing-log-api ;- HighStanza IntOps need to be lowered to sequences of primitive ops. ;- Call commands need to be broken up into register and memory arguments. @@ -19,6 +20,12 @@ defpackage stz/vm-normalize : ;- CallClosures need to be lowered. ;- External Memory Locations +;============================================================ +;====================== Timers ============================== +;============================================================ + +val VM-NORMALIZE = TimerLabel("VM Normalize") + ;============================================================ ;==================== Driver ================================ ;============================================================ @@ -34,13 +41,14 @@ public defn name (p:NormVMPackage) : name(vmpackage(p)) public defn normalize (prog:VMPackage, backend:Backend) -> NormVMPackage : - val iotable = IOTable(packageio(prog)) - val extern-table = to-intset(seq(fid, extern-defns(prog))) - val databuffer = DataBuffer(prog) - val funcs* = for f in funcs(prog) map : - val func* = normalize(func(f), databuffer, backend, iotable, extern-table[id(f)]) - sub-func(f, func*) - NormVMPackage(sub-funcs(prog, funcs*), datas(databuffer)) + within log-time(VM-NORMALIZE, suffix(name(prog))) : + val iotable = IOTable(packageio(prog)) + val extern-table = to-intset(seq(fid, extern-defns(prog))) + val databuffer = DataBuffer(prog) + val funcs* = for f in funcs(prog) map : + val func* = normalize(func(f), databuffer, backend, iotable, extern-table[id(f)]) + sub-func(f, func*) + NormVMPackage(sub-funcs(prog, funcs*), datas(databuffer)) ;============================================================ ;=================== Main Algorithm ========================= diff --git a/compiler/vm.stanza b/compiler/vm.stanza index c1748c9ef..838e9305a 100644 --- a/compiler/vm.stanza +++ b/compiler/vm.stanza @@ -19,6 +19,7 @@ defpackage stz/vm : import stz/jit-code-table import stz/vm-structures import stz/params + import stz/timing-log-api ;======================================================= ;================= Virtual Machine Interface ================ @@ -84,6 +85,12 @@ in all packages. ;============================================================ ;======================================================= +;============================================================ +;======================== Timers ============================ +;============================================================ + +val EXEC-PACKAGE = TimerLabel("VM Execute Package") + ;============================================================ ;======================= Linker ============================= ;============================================================ @@ -858,13 +865,14 @@ lostanza defn set-core-loaded? (vm:ref, v:ref) -> re public defn init-package (vm:VirtualMachine, package:Symbol) -> True|False : val f = package-init(vm-ids(vm), package) match(f:Int) : - val trace? = false - if package == `core : - run-bytecode(vm, f) - set-core-loaded?(vm, true) - true - else : - launch-init(vm, f) + within log-time(EXEC-PACKAGE, suffix(package)) : + val trace? = false + if package == `core : + run-bytecode(vm, f) + set-core-loaded?(vm, true) + true + else : + launch-init(vm, f) else : true diff --git a/core/core.stanza b/core/core.stanza index 679326bc7..5d6d49d57 100644 --- a/core/core.stanza +++ b/core/core.stanza @@ -6446,24 +6446,23 @@ public defn IndentedStream (o:OutputStream) : IndentedStream(o, 2) public defn IndentedStream (o:OutputStream, n:Int) : - match(o) : - (o:IndentedStream) : - IndentedStream(stream(o), n + indent(o)) - (o) : - var start-of-line? = true - val spaces = String(n, ' ') - defn put (c:Char) : - if c == '\n' : - print(o, c) - start-of-line? = true - else : - print(o, spaces) when start-of-line? - print(o, c) - start-of-line? = false - new IndentedStream : - defmethod stream (this) : o - defmethod indent (this) : n - defmethod print (this, c:Char) : put(c) + IndentedStream(o, 2, true) + +public defn IndentedStream (o:OutputStream, n:Int, initial-start-of-line?:True|False) : + var start-of-line? = initial-start-of-line? + val spaces = String(n, ' ') + defn put (c:Char) : + if c == '\n' : + print(o, c) + start-of-line? = true + else : + print(o, spaces) when start-of-line? + print(o, c) + start-of-line? = false + new IndentedStream : + defmethod stream (this) : o + defmethod indent (this) : n + defmethod print (this, c:Char) : put(c) public deftype Indented public defmulti item (x:Indented) -> ?