Skip to content

Commit a1fbc5c

Browse files
committed
New dircat for files
1 parent 0beab9f commit a1fbc5c

5 files changed

Lines changed: 79 additions & 1 deletion

File tree

stc/code/src/exm/stc/common/lang/Operators.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,22 @@ private static void fillArithOps() {
159159
}
160160
}
161161

162+
/*
163+
* Allow the directory catenation operator (/) to take file operands as
164+
* well as strings: a file contributes its filename. The result is
165+
* always a string. The frontend replaces each file operand with its
166+
* filename future, so the underlying DIRCAT op still sees only strings.
167+
*/
168+
OpInputType dircatFile = new OpInputType(Types.F_FILE, false);
169+
OpInputType dircatString = new OpInputType(Types.F_STRING, false);
170+
for (List<OpInputType> dircatArgs:
171+
Arrays.asList(Arrays.asList(dircatFile, dircatString),
172+
Arrays.asList(dircatString, dircatFile),
173+
Arrays.asList(dircatFile, dircatFile))) {
174+
registerOverload(ExMParser.DIV, BuiltinOpcode.DIRCAT,
175+
new OpType(Types.F_STRING, dircatArgs));
176+
}
177+
162178
Type sprintfArg = UnionType.createUnionType(Types.F_STRING, Types.F_INT, Types.F_FLOAT, Types.F_BOOL);
163179
List<OpInputType> sprintfArgs = Arrays.asList(new OpInputType(Types.F_STRING, false),
164180
new OpInputType(sprintfArg, true));
@@ -176,6 +192,15 @@ private static void registerOperator(int token, BuiltinOpcode opCode,
176192
arithOps.put(token, new Op(opCode, opType));
177193
}
178194

195+
/**
196+
* Register an extra overload for an operator, leaving the canonical type
197+
* recorded for the opcode alone.
198+
*/
199+
private static void registerOverload(int token, BuiltinOpcode opCode,
200+
OpType opType) {
201+
arithOps.put(token, new Op(opCode, opType));
202+
}
203+
179204
private static String getOpTypeName(PrimType numType) {
180205
switch (numType) {
181206
case BOOL:

stc/code/src/exm/stc/frontend/ExprWalker.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,12 +599,31 @@ private void callOperator(Context context, SwiftAST tree,
599599
} else {
600600
// Store into temporary variables
601601
Var arg = eval(context, tree.child(i + 1), exprType, false, renames);
602+
if (Types.isFile(arg)) {
603+
// Operators work on strings: a file operand contributes its
604+
// filename. Used by the directory catenation operator (/).
605+
arg = filenameOf(context, arg);
606+
}
602607
iList.add(Arg.newVar(arg));
603608
}
604609
}
605610
asyncOp(op.code, out, iList);
606611
}
607612

613+
/**
614+
* Get a string future aliasing the filename of a file variable.
615+
* @param context
616+
* @param fileVar a file
617+
* @return string future holding the filename
618+
*/
619+
private Var filenameOf(Context context, Var fileVar)
620+
throws UserException, UndefinedTypeException {
621+
Var filename = varCreator.createFilenameAlias(context, fileVar);
622+
backend.getFileNameAlias(VarRepr.backendVar(filename),
623+
VarRepr.backendVar(fileVar), false);
624+
return filename;
625+
}
626+
608627

609628
/**
610629
* Evaluate a tuple expression.

stc/code/src/exm/stc/frontend/VariableUsageAnalyzer.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,15 @@ private void walkExpr(Context context, VariableUsageInfo vu,
715715
case ExMParser.OPERATOR:
716716
// Walk argument expressions
717717
// skip the first child, which is the operator name
718+
boolean dircat = node.child(0).getType() == ExMParser.DIV;
718719
for (int i = 1; i < node.getChildCount(); i++) {
719-
exprNodes.push(node.child(i));
720+
SwiftAST arg = node.child(i);
721+
if (dircat && filenameOnlyUse(vu, arg)) {
722+
// Directory catenation uses only a file's name, not its
723+
// contents, so the file need not be written
724+
continue;
725+
}
726+
exprNodes.push(arg);
720727
}
721728
break;
722729
case ExMParser.ARRAY_RANGE:
@@ -786,6 +793,22 @@ private void walkExpr(Context context, VariableUsageInfo vu,
786793
}
787794

788795

796+
/**
797+
* Check whether an operand is a plain file variable. The directory
798+
* catenation operator (/) uses such an operand only for its filename, so
799+
* it does not count as a read of the file's contents.
800+
* @param vu variable usage info for the enclosing scope
801+
* @param arg operand expression
802+
*/
803+
private boolean filenameOnlyUse(VariableUsageInfo vu, SwiftAST arg) {
804+
if (arg.getType() != ExMParser.VARIABLE) {
805+
return false;
806+
}
807+
VariableUsageInfo.VInfo vi =
808+
vu.lookupVariableInfo(arg.child(0).getText());
809+
return vi != null && Types.isFile(vi.getType());
810+
}
811+
789812
private void walkTopLevelModule(Context fnContext, ParsedModule module,
790813
VariableUsageInfo topLevelVui, Set<ParsedModule> visited)
791814
throws UserException {

stc/tests/676-dircat-file.exp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
trace: dir_676/file.txt,dir_676/sub,top/leaf.txt,dir_676/leaf.txt

stc/tests/676-dircat-file.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
// Tests the directory catenation operator (/) applied to files.
3+
// A file operand contributes its filename; the result is a string.
4+
5+
file d<"dir_676">;
6+
file f<"leaf.txt">;
7+
s = "sub";
8+
9+
// file/string, file/string, string/file, file/file
10+
trace(d/"file.txt", d/s, "top"/f, d/f);

0 commit comments

Comments
 (0)