Skip to content

Commit

Permalink
Merge branch 'fix-aux-file'
Browse files Browse the repository at this point in the history
  • Loading branch information
CuppoJava committed Nov 30, 2022
2 parents 24d25e2 + 11fbcb0 commit 289f72f
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 56 deletions.
8 changes: 8 additions & 0 deletions compiler/aux-file-serializer.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ defserializer AuxFileSerializer () :
RequiresStmt: (package:symbol, ccfiles:tuple(string), ccflags:tuple(string-or-tuple), foreign-packages:tuple(foreign-package))
ImportWhenStmt: (package:symbol, dependencies:tuple(symbol))
CompileStmt: (file?:bool, name:string-or-tuple, dependencies:tuple(string), foreign-packages:tuple(foreign-package), commands:tuple(string))
ForeignPackageParamsStmt: (package-manager:symbol, projdir:string, entries:tuple(keyvalue(symbol,projitem)))

defunion projitem (?) :
Symbol: symbol
String: string
Tuple: tuple(projitem)
List: list(projitem)
ProjTable: (entries:tuple(keyvalue(symbol,projitem)))

defunion string-or-symbol (String|Symbol) :
String : string
Expand Down
2 changes: 2 additions & 0 deletions compiler/fastio-errors.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ defmethod print (o:OutputStream, e:FastIOIncludeError) :

;Generic error occurred during writing.
public defstruct FastIOSerializationError <: FastIOError
defmethod print (o:OutputStream, e:FastIOSerializationError) :
print(o, "Error occurred in FastIO serialization.")

;Return the info header.
defn info-str (info:FileInfo|False) :
Expand Down
2 changes: 1 addition & 1 deletion compiler/params.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public defn compiler-flags () :
to-tuple(COMPILE-FLAGS)

;========= Stanza Configuration ========
public val STANZA-VERSION = [0 17 43]
public val STANZA-VERSION = [0 17 44]
public var STANZA-INSTALL-DIR:String = ""
public var OUTPUT-PLATFORM:Symbol = `platform
public var STANZA-PKG-DIRS:List<String> = List()
Expand Down
4 changes: 2 additions & 2 deletions compiler/preparsed-template.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public defn PreparsedTemplate (base:Symbol,
PreparsedTemplate :

;Ensure that the template is a valid s-expression.
check-valid-sexp(template)
check-valid-sexp(template,true)

;Create tables for mapping symbols.
val binder-to-gensym = HashTable<Symbol,Symbol>()
Expand Down Expand Up @@ -129,7 +129,7 @@ public defn PreparsedTemplate (base:Symbol,
;Ensure that the entries are correct.
#if-not-defined(OPTIMIZE) :
for entry in entries do :
try : check-valid-sexp(value(entry))
try : check-valid-sexp(value(entry),true)
catch (e) : fatal(e)

for entry in entries do :
Expand Down
8 changes: 6 additions & 2 deletions compiler/proj-ir.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ public defenum BuildTargetType :
StandardTarget
TestTarget

public defstruct ForeignPackageParamsStmt <: ProjStmt :
public defstruct ForeignPackageParamsStmt <: ProjStmt & Equalable :
package-manager:Symbol
projdir: String
entries: Tuple<KeyValue<Symbol, ?>>
with:
equalable => true

;============================================================
;======================= Values =============================
Expand All @@ -94,8 +96,10 @@ public defstruct ForeignPackageParamsStmt <: ProjStmt :
; email: "[email protected]"
; path: "build/dir"
; }
public defstruct ProjTable :
public defstruct ProjTable <: Equalable :
entries:Tuple<KeyValue<Symbol,?>>
with:
equalable => true

defmethod print (o:OutputStream, v:ProjTable) :
defn str (e:KeyValue<Symbol,?>) : "%~: %~" % [key(e), value(e)]
Expand Down
143 changes: 95 additions & 48 deletions compiler/proj-utils.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defpackage stz/proj-utils :
import collections
import stz/proj-ir
import stz/printing-utils
import stz/foreign-package-files

;============================================================
;===================== Algorithm ============================
Expand All @@ -29,13 +30,18 @@ defpackage stz/proj-utils :
; RequiresStmt
; - Relevant if package is in the root set.
; - If relevant, then also determine what affects ccfiles and ccflags.
; - If relevant, then the foreign package manager is also relevant.
;
; ImportWhenStmt
; - Relevant if package is in the root set.
; - Relevant if any dependencies are in the root set.
;
; CompileStmt
; - Relevant if file or flag is a ccfile/ccflag that affects the root set.
; - If relevant, then the foreign package manager is also relevant.
;
; ForeignPackageParamsStmt
; - Relevant if this foreign package manager has been deemed relevant.
;
; BuildStmt
; - These never affect another build target.
Expand Down Expand Up @@ -67,72 +73,112 @@ defmethod print (o:OutputStream, p:ProjIsolate) :

public defn isolate-stmts (proj:ProjFile, root-packages:Tuple<Symbol>) -> ProjIsolate :
;Initialize root keys
val root-keys = HashSet<StmtKey>()
for p in root-packages do : add(root-keys, PackageKey(p))
val relevant-items = HashSet<ProjItem>()
for p in root-packages do : add(relevant-items, PackageItem(p))
for stmt in filter-by<RequiresStmt>(stmts(proj)) do :
if root-keys[PackageKey(package(stmt))] :
for f in ccfiles(stmt) do : add(root-keys,FileKey(f))
for f in ccflags(stmt) do : add(root-keys,FlagKey(f))
if relevant-items[PackageItem(package(stmt))] :
for f in ccfiles(stmt) do :
add(relevant-items,CCFileItem(f))
for f in ccflags(stmt) do :
add(relevant-items,CCFlagItem(f))
for f in foreign-packages(stmt) do :
add(relevant-items,PackageManagerItem(package-manager(f)))

;Initialize package tree
val package-tree = PackageTree(root-packages)

;Filter stmts. Return true if the given ProjStmt
;is relevant to the set of root packages.
defn relevant? (s:ProjStmt) -> True|False :
match(s) :
(s:PackagesDefinedInStmt) :
non-empty-root?(package-tree, packages(s))
(s) :
label<True|False> return :
within k = keys(s) :
return(true) when root-keys[k]
label<True|False> return :
match(s) :
(s:PackagesDefinedInStmt) :
non-empty-root?(package-tree, packages(s))
(s) :
within item = main-items(s) :
return(true) when relevant-items[item]

;Return isolate
ProjIsolate(
root-packages,
qsort(root-packages),
to-tuple(filter(relevant?, stmts(proj))))

;------------------------------------------------------------
;--------------------- Graph Edges --------------------------
;--------------------- Main Item ----------------------------
;------------------------------------------------------------
defn keys (return:StmtKey -> ?, s:ProjStmt) -> ? :
;Given the set of all relevant proj items in the program,
;we can sweep through each ProjStmt and ask whether it is relevant.
;We define a statement as "relevant" if any of its "main items"
;appear in the relevant item set.
;
;Here is a nuanced example: For the RequiresStmt, if the package
;appears in the set of relevant proj items, then obviously the RequiresStmt
;is relevant. However, even if the ccfiles themselves appear
;in the set of relevant proj items, it does *not* imply that the
;RequiresStmt is relevant.

defn main-items (return:ProjItem -> ?, s:ProjStmt) -> ? :
match(s) :
(s:DefinedInStmt) :
return(PackageKey(package(s)))
(s:RequiresStmt) :
return(PackageKey(package(s)))
;Additionally include the dependencies of an import-when statement.
(s:ImportWhenStmt) :
return(PackageKey(package(s)))
for d in dependencies(s) do : return(PackageKey(d))
(s:CompileStmt) :
if file?(s) : return(FileKey(name(s) as String))
else : return(FlagKey(name(s)))
return(main-item(s))
for d in dependencies(s) do : return(PackageItem(d))
;Build statements are never relevant.
(s:BuildStmt) :
false
;All other statements only have one main item.
(s:ProjStmt) :
return(main-item(s))

;The main-item of a statement is used to match one
;statement against another when comparing isolates.
defn main-item (s:ProjStmt) -> ProjItem :
match(s) :
(s:DefinedInStmt) : PackageItem(package(s))
(s:RequiresStmt) : PackageItem(package(s))
(s:ImportWhenStmt) : PackageItem(package(s))
(s:CompileStmt) :
if file?(s) : CCFileItem(name(s) as String)
else : CCFlagItem(name(s))
(s:ForeignPackageParamsStmt) :
PackageManagerItem(package-manager(s))

;------------------------------------------------------------
;-------------------- StmtKey Utility -----------------------
;-------------------- ProjItem Utility ----------------------
;------------------------------------------------------------
deftype StmtKey <: Equalable & Hashable
defstruct PackageKey <: StmtKey :

;Structured representation of an 'item' in the .proj file.
;Used to indicate that an item is relevant.
deftype ProjItem <: Equalable & Hashable & Comparable<ProjItem>

;Represents a Stanza package.
defstruct PackageItem <: ProjItem :
name:Symbol
with:
equalable => true
hashable => true

defstruct FileKey <: StmtKey :
;Represents an external C file.
defstruct CCFileItem <: ProjItem :
filename:String
with:
equalable => true
hashable => true

defstruct FlagKey <: StmtKey :
;Represents an external C flag.
defstruct CCFlagItem <: ProjItem :
name:String|Tuple<String>
with:
equalable => true
hashable => true

;Represents a foreign package manager.
defstruct PackageManagerItem <: ProjItem :
name:Symbol
with:
equalable => true
hashable => true

;============================================================
;==================== Package Tree ==========================
;============================================================
Expand Down Expand Up @@ -185,23 +231,24 @@ defn non-empty-root? (tree:PackageTree, root:Symbol|False) -> True|False :
;=================== Isolate Isomorphism ====================
;============================================================

public defn isomorphic? (a:ProjIsolate, b:ProjIsolate) :
if packages(a) == packages(b) :
if length(stmts(a)) == length(stmts(b)) :
val atable = to-hashtable<?,ProjStmt&Equalable> $
for s in stmts(a) seq : key(s) => s as ProjStmt&Equalable
for s in stmts(b) all? :
(s as ProjStmt&Equalable) == get?(atable, key(s))

defn key (s:ProjStmt) -> ? :
;Return an arbitrary integer so that we can group statements
;by type.
defn type-tag (s:ProjStmt) -> Int :
match(s) :
(s:DefinedInStmt) :
[`defined, package(s)]
(s:PackagesDefinedInStmt) :
[`packages-defined, packages(s)]
(s:RequiresStmt) :
[`requires, package(s)]
(s:ImportWhenStmt) :
[`import-when, package(s)]
(s:CompileStmt) :
[`compile-file when file?(s) else `compile-flag, name(s)]
(s:DefinedInStmt) : 0
(s:RequiresStmt) : 1
(s:ImportWhenStmt) : 2
(s:CompileStmt) : 3
(s:ForeignPackageParamsStmt) : 4

;Return true if two extracted isolates are equal to each other.
public defn isomorphic? (a:ProjIsolate, b:ProjIsolate) -> True|False :
if packages(a) == packages(b) and
length(stmts(a)) == length(stmts(b)) :
val atable = to-hashtable<[Int,ProjItem],ProjStmt&Equalable> $
for s in stmts(a) seq :
val key = [type-tag(s), main-item(s)]
key => s as ProjStmt&Equalable
for s in stmts(b) all? :
val key = [type-tag(s), main-item(s)]
(s as ProjStmt&Equalable) == get?(atable, key)
20 changes: 17 additions & 3 deletions compiler/sexp-checker.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defpackage stz/sexp-checker :
;Scan through the given s-expression and ensure it is valid.
;If it is not, throw a InvalidSExp error.

public defn check-valid-sexp (sexp) -> False :
public defn check-valid-sexp (sexp,
allow-rich-quotes?:True|False) -> False :

;Track the most recent information seen.
var closest-info:FileInfo|False = false
Expand All @@ -30,7 +31,11 @@ public defn check-valid-sexp (sexp) -> False :
update-info(info(sexp))
loop(item(sexp))
(sexp:List) :
do(loop, sexp)
if quote-form?(sexp) :
if not allow-rich-quotes? :
do(loop, sexp)
else :
do(loop, sexp)
(sexp:Char
|Byte|Int|Long
|Float|Double
Expand All @@ -42,4 +47,13 @@ public defn check-valid-sexp (sexp) -> False :
add(error-buffer, err)

;Issue errors
throw-errors?()
throw-errors?()

;By default, allow-rich-quotes? is false.
public defn check-valid-sexp (sexp) -> False :
check-valid-sexp(sexp, false)

;Helper: Return true if it's a ($quote ...) form.
defn quote-form? (x:List) -> True|False :
not empty?(x) and
unwrap-token(head(x)) == `$quote

0 comments on commit 289f72f

Please sign in to comment.