Skip to content

Commit

Permalink
convert infix node to take any 2+ number of args
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalMarsalek committed Mar 14, 2024
1 parent 8f687e4 commit e87c15c
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 50 deletions.
10 changes: 4 additions & 6 deletions src/IR/exprs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ export interface RangeIndexCall extends BaseNode {
export interface Infix extends BaseNode {
readonly kind: "Infix";
readonly name: string;
readonly left: Node;
readonly right: Node;
readonly args: [Node, Node, ...Node[]];
}

export interface Prefix extends BaseNode {
Expand Down Expand Up @@ -495,12 +494,11 @@ export function rangeIndexCall(
};
}

export function infix(name: string, left: Node, right: Node): Infix {
export function infix(name: string, ...args: [Node, Node, ...Node[]]): Infix {
return {
kind: "Infix",
left,
right,
name,
args,
};
}

Expand Down Expand Up @@ -567,7 +565,7 @@ export function getArgs(
): readonly Node[] {
switch (node.kind) {
case "Infix":
return [node.left, node.right];
return node.args;
case "Prefix":
return [node.arg];
case "FunctionCall":
Expand Down
16 changes: 15 additions & 1 deletion src/common/Language.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Node } from "IR";
import type { Infix, Node } from "IR";
import { Spine, type PluginVisitor, programToSpine } from "./Spine";
import { type CompilationContext } from "./compile";
import type {
Expand Down Expand Up @@ -93,6 +93,20 @@ export abstract class PrecedenceVisitorEmitter extends VisitorEmitter {
spine: Spine,
context: CompilationContext,
): EmitterVisitResult;
infixChildPrecForNoParens(
parent: Infix,
fragment: PathFragment,
...rightAssociative: string[]
) {
const indexThatDoesntNeedHigherPrec = rightAssociative.includes(parent.name)
? parent.args.length - 1
: 0;
return (
this.prec(parent) +
Number(indexThatDoesntNeedHigherPrec !== fragment.index)
);
}

visit(node: Node, spine: Spine, context: CompilationContext) {
const res = this.visitNoParens(node, spine, context);
const minPrec =
Expand Down
2 changes: 0 additions & 2 deletions src/common/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,8 @@ const childProps = [
"index",
"init",
"key",
"left",
"low",
"object",
"right",
"step",
"value",
"variable",
Expand Down
7 changes: 5 additions & 2 deletions src/frontend/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,11 @@ export function sexpr(
expectArity(2, Infinity);
return methodCall(args[0], asString(args[1]), ...args.slice(2));
case "infix":
expectArity(3);
return infix(asString(args[0]), args[1], args[2]);
expectArity(3, Infinity);
return infix(
asString(args[0]),
...(args.slice(1) as [Node, Node, ...Node[]]),
);
case "prefix":
expectArity(2);
return prefix(asString(args[0]), args[1]);
Expand Down
6 changes: 2 additions & 4 deletions src/languages/javascript/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ export class JavascriptEmitter extends PrecedenceVisitorEmitter {
? -Infinity
: this.prec(parent)
: kind === "Infix"
? prop === "left"
? this.prec(parent) + (parent.name === "**" ? 1 : 0)
: this.prec(parent) + (parent.name === "**" ? 0 : 1)
? this.infixChildPrecForNoParens(parent, fragment, "**")
: kind === "Prefix" || kind === "Postfix"
? this.prec(parent)
: -Infinity;
Expand Down Expand Up @@ -221,7 +219,7 @@ export class JavascriptEmitter extends PrecedenceVisitorEmitter {
case "PropertyCall":
return [$.object, ".", $.ident];
case "Infix":
return [$.left, n.name, $.right];
return $.args.join(n.name);
case "Prefix":
return [n.name, $.arg];
case "Postfix":
Expand Down
8 changes: 3 additions & 5 deletions src/languages/lua/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,8 @@ export class LuaEmitter extends PrecedenceVisitorEmitter {
: kind === "IndexCall" && prop === "collection"
? Infinity
: kind === "Infix"
? prop === "left"
? this.prec(parent) + (parent.name === "^" ? 1 : 0)
: this.prec(parent) + (parent.name === "^" ? 0 : 1)
: kind === "Prefix"
? this.infixChildPrecForNoParens(parent, fragment, "^")
: kind === "Prefix" || kind === "Postfix"
? this.prec(parent)
: -Infinity;
}
Expand Down Expand Up @@ -148,7 +146,7 @@ export class LuaEmitter extends PrecedenceVisitorEmitter {
case "MethodCall":
return [$.object, ":", $.ident, "(", $.args.join(","), ")"];
case "Infix":
return [$.left, e.name, $.right];
return $.args.join(e.name);
case "Prefix":
return [e.name, $.arg];
case "IndexCall":
Expand Down
13 changes: 9 additions & 4 deletions src/languages/nim/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ export class NimEmitter extends PrecedenceVisitorEmitter {
: kind === "Infix"
? this.prec(parent) +
Number(
(parent.name === "^" || parent.name === " ") === (prop === "left"),
(parent.name === "^" || parent.name === " ") ===
(fragment.index === 0),
)
: kind === "Prefix" || kind === "Postfix"
? this.prec(parent)
Expand Down Expand Up @@ -222,13 +223,17 @@ export class NimEmitter extends PrecedenceVisitorEmitter {
return [$.func, "$GLUE$", "(", $.args.join(","), ")"];
case "Infix": {
if (n.name === "") {
return [$.left, "$GLUE$", emitAsRawText((n.right as Text).value)];
return [
$.args.at(0),
"$GLUE$",
emitAsRawText((n.args[1] as Text).value),
];
}
return [
$.left,
$.args.at(0),
/[A-Za-z]/.test(n.name[0]) ? [] : "$GLUE$",
n.name,
$.right,
$.args.at(1),
];
}
case "Prefix":
Expand Down
32 changes: 16 additions & 16 deletions src/languages/nim/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@ export function useUFCS(node: Node) {
);
}
}
if (node.kind === "Infix" && node.name === " " && isIdent()(node.left)) {
return infix(".", node.right, node.left);
if (node.kind === "Infix" && node.name === " " && node.args.length === 2) {
const [left, right] = node.args;
if (isIdent()(left)) {
return infix(".", right, left);
}
}
}

Expand Down Expand Up @@ -151,20 +154,17 @@ export function useRawStringLiteral(
spine: Spine,
context: CompilationContext,
) {
if (
node.kind === "Infix" &&
node.name === " " &&
isText()(node.right) &&
(isIdent()(node.left) ||
(node.left.kind === "Infix" && node.left.name === "."))
) {
const [low, high] = context.options.codepointRange;
if (low === 1 && high === Infinity) {
if (
!node.right.value.includes("\n") &&
!node.right.value.includes("\r")
) {
return infix("", node.left, node.right);
if (node.kind === "Infix" && node.name === " " && node.args.length === 2) {
const [left, right] = node.args;
if (
isText()(right) &&
(isIdent()(left) || (left.kind === "Infix" && left.name === "."))
) {
const [low, high] = context.options.codepointRange;
if (low === 1 && high === Infinity) {
if (!right.value.includes("\n") && !right.value.includes("\r")) {
return infix("", left, right);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/languages/polygolf/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export function emitNodeWithoutAnnotation(
case "PropertyCall":
return emitSexpr(null, expr.object, text(expr.ident.name));
case "Infix":
return emitSexpr(null, text(expr.name), expr.left, expr.right);
return emitSexpr(null, text(expr.name), ...expr.args);
case "Prefix":
case "Postfix":
return emitSexpr(null, text(expr.name), expr.arg);
Expand Down
6 changes: 2 additions & 4 deletions src/languages/python/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,7 @@ export class PythonEmitter extends PrecedenceVisitorEmitter {
: kind === "ConditionalOp"
? this.prec(parent) + (prop === "alternate" ? 0 : 1)
: kind === "Infix"
? prop === "left"
? this.prec(parent) + (parent.name === "**" ? 1 : 0)
: this.prec(parent) + (parent.name === "**" ? 0 : 1)
? this.infixChildPrecForNoParens(parent, fragment, "**")
: kind === "Prefix" || kind === "Postfix"
? this.prec(parent)
: -Infinity;
Expand Down Expand Up @@ -206,7 +204,7 @@ export class PythonEmitter extends PrecedenceVisitorEmitter {
case "PropertyCall":
return [$.object, ".", $.ident];
case "Infix":
return [$.left, n.name, $.right];
return $.args.join(n.name);
case "Prefix":
return [n.name, $.arg];
case "Set":
Expand Down
10 changes: 6 additions & 4 deletions src/languages/swift/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,11 @@ export class SwiftEmitter extends PrecedenceVisitorEmitter {
: prop === "consequent"
? -Infinity
: this.prec(parent)
: kind === "Infix" || kind === "Prefix" || kind === "Postfix"
? this.prec(parent) + (prop === "right" ? 1 : 0)
: -Infinity;
: kind === "Infix"
? this.infixChildPrecForNoParens(parent, fragment)
: kind === "Prefix" || kind === "Postfix"
? this.prec(parent)
: -Infinity;
}

visitNoParens(n: Node, spine: Spine, context: CompilationContext) {
Expand Down Expand Up @@ -182,7 +184,7 @@ export class SwiftEmitter extends PrecedenceVisitorEmitter {
case "ConditionalOp":
return [$.condition, "?", $.consequent, ":", $.alternate];
case "Infix": {
return [$.left, n.name, $.right];
return $.args.join(n.name);
}
case "Prefix":
return [n.name, $.arg];
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/ops.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const propertyOpMapper: OpMapper<string> = (arg, [first]) =>
export const prefixOpMapper: OpMapper<string> = (arg, opArgs) =>
prefix(arg, opArgs[0]);
export const infixOpMapper: OpMapper<string> = (arg, opArgs) =>
infix(arg, opArgs[0], opArgs[1]);
infix(arg, ...(opArgs as [Node, Node, ...Node[]]));
export const postfixOpMapper: OpMapper<string> = (arg, opArgs) =>
postfix(arg, opArgs[0]);
export const indexOpMapper: OpMapper<0 | 1> = (arg, opArgs) => {
Expand Down

0 comments on commit e87c15c

Please sign in to comment.