mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: match expr first half
This commit is contained in:
parent
5c9e3ce73f
commit
8f3523d4e1
@ -148,6 +148,7 @@ export type ExprKind =
|
||||
| { tag: "binary" } & BinaryExpr
|
||||
| { tag: "block" } & BlockExpr
|
||||
| { tag: "if" } & IfExpr
|
||||
| { tag: "match" } & MatchExpr
|
||||
| { tag: "loop" } & LoopExpr
|
||||
| { tag: "while" } & WhileExpr
|
||||
| { tag: "for" } & ForExpr
|
||||
@ -171,11 +172,18 @@ export type UnaryExpr = { unaryType: UnaryType; expr: Expr };
|
||||
export type BinaryExpr = { binaryType: BinaryType; left: Expr; right: Expr };
|
||||
export type BlockExpr = { block: Block };
|
||||
export type IfExpr = { cond: Expr; truthy: Expr; falsy?: Expr };
|
||||
export type MatchExpr = { expr: Expr; arms: MatchArm[] };
|
||||
export type LoopExpr = { body: Expr };
|
||||
export type WhileExpr = { cond: Expr; body: Expr };
|
||||
export type ForExpr = { pat: Pat; expr: Expr; body: Expr };
|
||||
export type CForExpr = { decl?: Stmt; cond?: Expr; incr?: Stmt; body: Expr };
|
||||
|
||||
export type MatchArm = {
|
||||
pat: Pat;
|
||||
expr: Expr;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type RefType = "ref" | "ptr";
|
||||
export type UnaryType = "not" | "-";
|
||||
export type BinaryType =
|
||||
@ -213,10 +221,20 @@ export type Pat = {
|
||||
export type PatKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "bind" } & BindPat
|
||||
| { tag: "path" } & PathPat;
|
||||
| { tag: "path" } & PathPat
|
||||
| { tag: "tuple" } & TuplePat
|
||||
| { tag: "struct" } & StructPat;
|
||||
|
||||
export type BindPat = { ident: Ident; mut: boolean };
|
||||
export type PathPat = { qty?: Ty; path: Path };
|
||||
export type TuplePat = { path?: Path; elems: Pat[] };
|
||||
export type StructPat = { path?: Path; fields: PatField[] };
|
||||
|
||||
export type PatField = {
|
||||
ident: Ident;
|
||||
pat: Pat;
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Ty = {
|
||||
id: AstId;
|
||||
|
@ -33,6 +33,8 @@ import {
|
||||
ItemStmt,
|
||||
LetStmt,
|
||||
LoopExpr,
|
||||
MatchArm,
|
||||
MatchExpr,
|
||||
ModBlockItem,
|
||||
ModFileItem,
|
||||
Param,
|
||||
@ -51,6 +53,8 @@ import {
|
||||
StringExpr,
|
||||
StructExpr,
|
||||
StructItem,
|
||||
StructPat,
|
||||
TuplePat,
|
||||
TupleTy,
|
||||
Ty,
|
||||
TypeAliasItem,
|
||||
@ -116,15 +120,20 @@ export interface Visitor<
|
||||
visitBinaryExpr?(expr: Expr, kind: BinaryExpr, ...p: P): R;
|
||||
visitBlockExpr?(expr: Expr, kind: BlockExpr, ...p: P): R;
|
||||
visitIfExpr?(expr: Expr, kind: IfExpr, ...p: P): R;
|
||||
visitMatchExpr?(expr: Expr, kind: MatchExpr, ...p: P): R;
|
||||
visitLoopExpr?(expr: Expr, kind: LoopExpr, ...p: P): R;
|
||||
visitWhileExpr?(expr: Expr, kind: WhileExpr, ...p: P): R;
|
||||
visitForExpr?(expr: Expr, kind: ForExpr, ...p: P): R;
|
||||
visitCForExpr?(expr: Expr, kind: CForExpr, ...p: P): R;
|
||||
|
||||
visitMatchArm?(arm: MatchArm, ...p: P): R;
|
||||
|
||||
visitPat?(pat: Pat, ...p: P): R;
|
||||
visitErrorPat?(pat: Pat, ...p: P): R;
|
||||
visitBindPat?(pat: Pat, kind: BindPat, ...p: P): R;
|
||||
visitPathPat?(pat: Pat, kind: PathPat, ...p: P): R;
|
||||
visitTuplePat?(pat: Pat, kind: TuplePat, ...p: P): R;
|
||||
visitStructPat?(pat: Pat, kind: StructPat, ...p: P): R;
|
||||
|
||||
visitTy?(ty: Ty, ...p: P): R;
|
||||
visitErrorTy?(ty: Ty, ...p: P): R;
|
||||
@ -453,6 +462,13 @@ export function visitExpr<
|
||||
visitExpr(v, kind.falsy, ...p);
|
||||
}
|
||||
return;
|
||||
case "match":
|
||||
if (v.visitMatchExpr?.(expr, kind, ...p) === "stop") return;
|
||||
visitExpr(v, kind.expr, ...p);
|
||||
for (const arm of kind.arms) {
|
||||
visitMatchArm(v, arm, ...p);
|
||||
}
|
||||
return;
|
||||
case "loop":
|
||||
if (v.visitLoopExpr?.(expr, kind, ...p) === "stop") return;
|
||||
visitExpr(v, kind.body, ...p);
|
||||
@ -484,6 +500,18 @@ export function visitExpr<
|
||||
exhausted(kind);
|
||||
}
|
||||
|
||||
export function visitMatchArm<
|
||||
P extends PM = [],
|
||||
>(
|
||||
v: Visitor<P>,
|
||||
arm: MatchArm,
|
||||
...p: P
|
||||
) {
|
||||
if (v.visitMatchArm?.(arm, ...p) === "stop") return;
|
||||
visitPat(v, arm.pat, ...p);
|
||||
visitExpr(v, arm.expr, ...p);
|
||||
}
|
||||
|
||||
export function visitPat<
|
||||
P extends PM = [],
|
||||
>(
|
||||
@ -504,6 +532,21 @@ export function visitPat<
|
||||
if (v.visitPathPat?.(pat, kind, ...p) === "stop") return;
|
||||
visitPath(v, kind.path, ...p);
|
||||
return;
|
||||
case "tuple":
|
||||
if (v.visitTuplePat?.(pat, kind, ...p) === "stop") return;
|
||||
kind.path && visitPath(v, kind.path, ...p);
|
||||
for (const pat of kind.elems) {
|
||||
visitPat(v, pat, ...p);
|
||||
}
|
||||
return;
|
||||
case "struct":
|
||||
if (v.visitStructPat?.(pat, kind, ...p) === "stop") return;
|
||||
kind.path && visitPath(v, kind.path, ...p);
|
||||
for (const field of kind.fields) {
|
||||
visitIdent(v, field.ident, ...p);
|
||||
visitPat(v, field.pat, ...p);
|
||||
}
|
||||
return;
|
||||
}
|
||||
exhausted(kind);
|
||||
}
|
||||
|
@ -88,6 +88,10 @@ export class Checker {
|
||||
return Ok(undefined);
|
||||
case "path":
|
||||
return todo();
|
||||
case "tuple":
|
||||
return todo();
|
||||
case "struct":
|
||||
return todo();
|
||||
}
|
||||
exhausted(k);
|
||||
}
|
||||
@ -230,6 +234,7 @@ export class Checker {
|
||||
case "binary":
|
||||
case "block":
|
||||
case "if":
|
||||
case "match":
|
||||
case "loop":
|
||||
case "while":
|
||||
case "for":
|
||||
@ -358,6 +363,8 @@ export class Checker {
|
||||
return this.checkBlock(k.block, expected);
|
||||
case "if":
|
||||
return this.checkIfExpr(expr, k, expected);
|
||||
case "match":
|
||||
return this.checkMatchExpr(expr, k, expected);
|
||||
case "loop":
|
||||
return this.checkLoopExpr(expr, k, expected);
|
||||
case "while":
|
||||
@ -760,6 +767,36 @@ export class Checker {
|
||||
return bothRes.val;
|
||||
}
|
||||
|
||||
private checkMatchExpr(
|
||||
expr: ast.Expr,
|
||||
kind: ast.MatchExpr,
|
||||
expected: Ty,
|
||||
): Ty {
|
||||
const ty = this.exprTy(kind.expr);
|
||||
for (const arm of kind.arms) {
|
||||
const res = this.assignPatTy(arm.pat, ty);
|
||||
if (!res.ok) {
|
||||
this.report(res.val, arm.pat.span);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const tyRes = kind.arms
|
||||
.reduce<Res<Ty, string>>((earlier, arm) => {
|
||||
if (!earlier.ok) {
|
||||
return earlier;
|
||||
}
|
||||
const exprTy = this.exprTy(arm.expr);
|
||||
return this.resolveTys(exprTy, earlier.val);
|
||||
}, Res.Ok(Ty({ tag: "null" })));
|
||||
if (!tyRes.ok) {
|
||||
this.report(tyRes.val, expr.span);
|
||||
this.exprTys.set(expr.id, Ty({ tag: "error" }));
|
||||
return Ty({ tag: "error" });
|
||||
}
|
||||
this.exprTys.set(expr.id, tyRes.val);
|
||||
return todo();
|
||||
}
|
||||
|
||||
private checkLoopExpr(
|
||||
expr: ast.Expr,
|
||||
kind: ast.LoopExpr,
|
||||
@ -911,15 +948,23 @@ export class Checker {
|
||||
}
|
||||
case "let": {
|
||||
this.checkLetStmt(patRes.kind.stmt, patRes.kind.kind);
|
||||
const ty = this.patTy(pat);
|
||||
this.patTys.set(pat.id, ty);
|
||||
return ty;
|
||||
return this.patTy(pat);
|
||||
}
|
||||
case "match": {
|
||||
this.checkMatchExpr(
|
||||
patRes.kind.expr,
|
||||
patRes.kind.kind,
|
||||
Ty({ tag: "unknown" }),
|
||||
);
|
||||
return this.patTy(pat);
|
||||
}
|
||||
}
|
||||
exhausted(patRes.kind);
|
||||
return todo();
|
||||
}
|
||||
case "path":
|
||||
case "tuple":
|
||||
case "struct":
|
||||
return todo();
|
||||
}
|
||||
exhausted(k);
|
||||
|
@ -119,9 +119,15 @@ export class Ctx {
|
||||
return this.maxSeverity >= severityCode.error;
|
||||
}
|
||||
|
||||
private amountReportedImmediately = 0;
|
||||
|
||||
public enableReportImmediately = false;
|
||||
public enableStacktrace = false;
|
||||
private reportImmediately(rep: Report) {
|
||||
if (this.amountReportedImmediately >= 2) {
|
||||
return;
|
||||
}
|
||||
this.amountReportedImmediately += 1;
|
||||
if (this.enableReportImmediately) {
|
||||
prettyPrintReport(this, rep);
|
||||
if (this.enableStacktrace) {
|
||||
|
@ -79,7 +79,7 @@ export function prettyPrintReport(ctx: Ctx, rep: Report) {
|
||||
"color: cyan",
|
||||
);
|
||||
console.error(
|
||||
`${rep.span.begin.line.toString().padStart(4, " ")}%c| %c${
|
||||
`%c${rep.span.begin.line.toString().padStart(4, " ")}| %c${
|
||||
spanLines[0]
|
||||
}`,
|
||||
"color: cyan",
|
||||
@ -92,6 +92,7 @@ export function prettyPrintReport(ctx: Ctx, rep: Report) {
|
||||
"color: cyan",
|
||||
`color: ${sevColor}; font-weight: bold`,
|
||||
);
|
||||
console.error(""); // empty newline
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < spanLines.length; i++) {
|
||||
@ -125,6 +126,7 @@ export function prettyPrintReport(ctx: Ctx, rep: Report) {
|
||||
);
|
||||
}
|
||||
}
|
||||
console.error(""); // empty newline
|
||||
} else if (rep.pos) {
|
||||
console.error(
|
||||
` %c|`,
|
||||
@ -142,6 +144,7 @@ export function prettyPrintReport(ctx: Ctx, rep: Report) {
|
||||
"color: cyan",
|
||||
`color: ${sevColor}; font-weight: bold`,
|
||||
);
|
||||
console.error(""); // empty newline
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,8 @@ export class FnLowerer {
|
||||
return;
|
||||
}
|
||||
case "path":
|
||||
case "tuple":
|
||||
case "struct":
|
||||
return todo();
|
||||
}
|
||||
exhausted(k);
|
||||
@ -172,6 +174,8 @@ export class FnLowerer {
|
||||
return;
|
||||
}
|
||||
case "path":
|
||||
case "tuple":
|
||||
case "struct":
|
||||
return todo();
|
||||
}
|
||||
exhausted(k);
|
||||
@ -246,6 +250,7 @@ export class FnLowerer {
|
||||
case "binary":
|
||||
case "block":
|
||||
case "if":
|
||||
case "match":
|
||||
case "loop":
|
||||
case "while":
|
||||
case "for":
|
||||
@ -292,6 +297,8 @@ export class FnLowerer {
|
||||
return this.lowerBlock(k.block);
|
||||
case "if":
|
||||
return this.lowerIfExpr(expr, k);
|
||||
case "match":
|
||||
return this.lowerMatchExpr(expr, k);
|
||||
case "loop":
|
||||
return this.lowerLoopExpr(expr, k);
|
||||
case "while":
|
||||
@ -507,6 +514,10 @@ export class FnLowerer {
|
||||
}
|
||||
}
|
||||
|
||||
private lowerMatchExpr(expr: ast.Expr, kind: ast.MatchExpr): RVal {
|
||||
return todo();
|
||||
}
|
||||
|
||||
private lowerLoopExpr(expr: ast.Expr, kind: ast.LoopExpr): RVal {
|
||||
const entryBlock = this.currentBlock!;
|
||||
const loopBlock = this.pushBlock();
|
||||
@ -681,6 +692,7 @@ export class FnLowerer {
|
||||
case "binary":
|
||||
case "block":
|
||||
case "if":
|
||||
case "match":
|
||||
case "loop":
|
||||
case "while":
|
||||
case "for":
|
||||
|
@ -291,6 +291,7 @@ const keywords = new Set([
|
||||
"while",
|
||||
"for",
|
||||
"in",
|
||||
"match",
|
||||
"mod",
|
||||
"pub",
|
||||
"use",
|
||||
@ -300,6 +301,7 @@ const keywords = new Set([
|
||||
const staticTokens = [
|
||||
"=",
|
||||
"==",
|
||||
"=>",
|
||||
"<",
|
||||
"<=",
|
||||
">",
|
||||
|
@ -14,8 +14,10 @@ import {
|
||||
Ident,
|
||||
Item,
|
||||
ItemKind,
|
||||
MatchArm,
|
||||
Param,
|
||||
Pat,
|
||||
PatField,
|
||||
Path,
|
||||
PathSegment,
|
||||
PatKind,
|
||||
@ -81,7 +83,9 @@ export class Parser {
|
||||
this.eatSemicolon();
|
||||
return expr;
|
||||
} else if (
|
||||
["{", "if", "loop", "while", "for"].some((tt) => this.test(tt))
|
||||
["{", "if", "match", "loop", "while", "for"].some((tt) =>
|
||||
this.test(tt)
|
||||
)
|
||||
) {
|
||||
const expr = this.parseMultiLineBlockExpr();
|
||||
return (this.stmt({ tag: "expr", expr }, expr.span));
|
||||
@ -139,6 +143,9 @@ export class Parser {
|
||||
if (this.test("if")) {
|
||||
return this.parseIf();
|
||||
}
|
||||
if (this.test("match")) {
|
||||
return this.parseMatch();
|
||||
}
|
||||
if (this.test("loop")) {
|
||||
return this.parseLoop();
|
||||
}
|
||||
@ -204,7 +211,9 @@ export class Parser {
|
||||
stmts.push(this.parseSingleLineBlockStmt());
|
||||
this.eatSemicolon();
|
||||
} else if (
|
||||
["{", "if", "loop", "while", "for"].some((tt) => this.test(tt))
|
||||
["{", "if", "match", "loop", "while", "for"].some((tt) =>
|
||||
this.test(tt)
|
||||
)
|
||||
) {
|
||||
const expr = this.parseMultiLineBlockExpr();
|
||||
const span = expr.span;
|
||||
@ -847,6 +856,53 @@ export class Parser {
|
||||
return this.expr({ tag: "if", cond, truthy, falsy }, pos);
|
||||
}
|
||||
|
||||
private parseMatch(): Expr {
|
||||
const begin = this.span();
|
||||
let end = begin;
|
||||
this.step();
|
||||
const expr = this.parseExpr(ExprRestricts.NoStructs);
|
||||
if (!this.test("{")) {
|
||||
this.report("expected '{'");
|
||||
return this.expr({ tag: "error" }, begin);
|
||||
}
|
||||
this.step();
|
||||
const arms: MatchArm[] = [];
|
||||
if (!this.done() && !this.test("}")) {
|
||||
let needsComma = false;
|
||||
while (!this.done() && !this.test("}")) {
|
||||
if (this.test(",")) {
|
||||
this.step();
|
||||
} else if (needsComma) {
|
||||
this.report("expected ','");
|
||||
}
|
||||
if (this.done() || this.test("}")) {
|
||||
break;
|
||||
}
|
||||
const pat = this.parsePat();
|
||||
if (!this.test("=>")) {
|
||||
this.report("expected '=>'");
|
||||
return this.expr({ tag: "error" }, begin);
|
||||
}
|
||||
this.step();
|
||||
needsComma = !["{", "if", "match", "loop", "while", "for"]
|
||||
.some((tt) => this.test(tt));
|
||||
const expr = this.parseExpr();
|
||||
arms.push({
|
||||
pat,
|
||||
expr,
|
||||
span: Span.fromto(pat.span, expr.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!this.test("}")) {
|
||||
this.report("expected '}'");
|
||||
return this.expr({ tag: "error" }, begin);
|
||||
}
|
||||
end = this.span();
|
||||
this.step();
|
||||
return this.expr({ tag: "match", expr, arms }, Span.fromto(begin, end));
|
||||
}
|
||||
|
||||
private parseBinary(rs: ExprRestricts): Expr {
|
||||
return this.parseOr(rs);
|
||||
}
|
||||
@ -1117,23 +1173,79 @@ export class Parser {
|
||||
}
|
||||
|
||||
private parsePat(): Pat {
|
||||
const pos = this.span();
|
||||
const begin = this.span();
|
||||
if (this.test("ident")) {
|
||||
const ident = this.parseIdent();
|
||||
return this.pat({ tag: "bind", ident, mut: false }, ident.span);
|
||||
const pathRes = this.parsePath();
|
||||
if (!pathRes.ok) {
|
||||
return this.pat({ tag: "error" }, begin);
|
||||
}
|
||||
const path = pathRes.val;
|
||||
if (this.test("(")) {
|
||||
const end: [Span] = [begin];
|
||||
const elems = this.parseDelimitedList(
|
||||
this.parsePatRes,
|
||||
")",
|
||||
",",
|
||||
end,
|
||||
);
|
||||
return this.pat(
|
||||
{ tag: "tuple", path, elems },
|
||||
Span.fromto(begin, end[0]),
|
||||
);
|
||||
}
|
||||
if (this.test("{")) {
|
||||
const fields = this.parseDelimitedList(
|
||||
this.parsePatField,
|
||||
"}",
|
||||
",",
|
||||
);
|
||||
return this.pat(
|
||||
{ tag: "struct", path: pathRes.val, fields },
|
||||
pathRes.val.span,
|
||||
);
|
||||
}
|
||||
if (path.segments.length === 1) {
|
||||
const ident = path.segments[0].ident;
|
||||
return this.pat({ tag: "bind", ident, mut: false }, ident.span);
|
||||
} else {
|
||||
return this.pat({ tag: "path", path }, path.span);
|
||||
}
|
||||
}
|
||||
if (this.test("mut")) {
|
||||
this.step();
|
||||
if (!this.test("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
return this.pat({ tag: "error" }, pos);
|
||||
return this.pat({ tag: "error" }, begin);
|
||||
}
|
||||
const ident = this.parseIdent();
|
||||
return this.pat({ tag: "bind", ident, mut: true }, pos);
|
||||
return this.pat({ tag: "bind", ident, mut: true }, begin);
|
||||
}
|
||||
this.report(`expected pattern, got '${this.current().type}'`, pos);
|
||||
this.report(`expected pattern, got '${this.current().type}'`, begin);
|
||||
this.step();
|
||||
return this.pat({ tag: "error" }, pos);
|
||||
return this.pat({ tag: "error" }, begin);
|
||||
}
|
||||
|
||||
private parsePatRes(): ParseRes<Pat> {
|
||||
return Res.Ok(this.parsePat());
|
||||
}
|
||||
|
||||
private parsePatField(): ParseRes<PatField> {
|
||||
if (!this.test("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
return Res.Err(undefined);
|
||||
}
|
||||
const ident = this.parseIdent();
|
||||
if (!this.test(":")) {
|
||||
this.report("expected ':'");
|
||||
return Res.Err(undefined);
|
||||
}
|
||||
this.step();
|
||||
const pat = this.parsePat();
|
||||
return Res.Ok({
|
||||
ident,
|
||||
pat,
|
||||
span: Span.fromto(ident.span, pat.span),
|
||||
});
|
||||
}
|
||||
|
||||
private parseTy(): Ty {
|
||||
|
@ -1,11 +1,15 @@
|
||||
|
||||
enum S {
|
||||
A,
|
||||
B,
|
||||
A(int),
|
||||
B { v: int },
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = S::A;
|
||||
let s = S::A(123);
|
||||
match s {
|
||||
S::A(v) => {},
|
||||
S::B { v: v } => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,7 +36,8 @@ export type PatResolve = {
|
||||
|
||||
export type PatResolveKind =
|
||||
| { tag: "fn_param"; item: ast.Item; kind: ast.FnItem; paramIdx: number }
|
||||
| { tag: "let"; stmt: ast.Stmt; kind: ast.LetStmt };
|
||||
| { tag: "let"; stmt: ast.Stmt; kind: ast.LetStmt }
|
||||
| { tag: "match"; expr: ast.Expr; kind: ast.MatchExpr };
|
||||
|
||||
export const ResolveError = (ident: ast.Ident): Resolve => ({
|
||||
ident,
|
||||
|
@ -121,9 +121,12 @@ export class Resolver implements ast.Visitor {
|
||||
|
||||
visitBlock(block: ast.Block): ast.VisitRes {
|
||||
this.fnBodiesToCheck.push([]);
|
||||
const outerSyms = this.syms;
|
||||
this.syms = new LocalSyms(this.syms);
|
||||
ast.visitStmts(this, block.stmts);
|
||||
this.popAndVisitFnBodies();
|
||||
block.expr && ast.visitExpr(this, block.expr);
|
||||
this.syms = outerSyms;
|
||||
return "stop";
|
||||
}
|
||||
|
||||
@ -289,6 +292,25 @@ export class Resolver implements ast.Visitor {
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitMatchExpr(expr: ast.Expr, kind: ast.MatchExpr): ast.VisitRes {
|
||||
ast.visitExpr(this, kind.expr);
|
||||
this.patResolveStack.push({ tag: "match", expr, kind });
|
||||
for (const arm of kind.arms) {
|
||||
ast.visitMatchArm(this, arm);
|
||||
}
|
||||
this.patResolveStack.pop();
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitMatchArm(arm: ast.MatchArm): ast.VisitRes {
|
||||
const outerSyms = this.syms;
|
||||
this.syms = new LocalSyms(this.syms);
|
||||
ast.visitPat(this, arm.pat);
|
||||
ast.visitExpr(this, arm.expr);
|
||||
this.syms = outerSyms;
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitBindPat(pat: ast.Pat, kind: ast.BindPat): ast.VisitRes {
|
||||
this.patResols.set(pat.id, { pat, kind: this.patResolveStack.at(-1)! });
|
||||
const res = this.syms.defVal(kind.ident, {
|
||||
@ -303,7 +325,30 @@ export class Resolver implements ast.Visitor {
|
||||
}
|
||||
|
||||
visitPathPat(pat: ast.Pat, kind: ast.PathPat): ast.VisitRes {
|
||||
todo(pat, kind);
|
||||
this.resolveTyPath(kind.path);
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitTuplePat(pat: ast.Pat, kind: ast.TuplePat): ast.VisitRes {
|
||||
if (!kind.path) {
|
||||
return todo();
|
||||
}
|
||||
this.resolveTyPath(kind.path);
|
||||
for (const elem of kind.elems) {
|
||||
ast.visitPat(this, elem);
|
||||
}
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitStructPat(pat: ast.Pat, kind: ast.StructPat): ast.VisitRes {
|
||||
if (!kind.path) {
|
||||
return todo();
|
||||
}
|
||||
this.resolveTyPath(kind.path);
|
||||
for (const field of kind.fields) {
|
||||
ast.visitPat(this, field.pat);
|
||||
}
|
||||
return "stop";
|
||||
}
|
||||
|
||||
visitPathTy(ty: ast.Ty, kind: ast.PathTy): ast.VisitRes {
|
||||
|
@ -23,7 +23,7 @@ export class HirStringifyer {
|
||||
case "item":
|
||||
return this.item(k.item);
|
||||
case "let": {
|
||||
return `let ${this.pat(k.pat)}${
|
||||
return `let ${this.pat(k.pat, d)}${
|
||||
k.expr && ` = ${this.expr(k.expr, d)}` || ""
|
||||
};`;
|
||||
}
|
||||
@ -43,7 +43,7 @@ export class HirStringifyer {
|
||||
exhausted(k);
|
||||
}
|
||||
|
||||
public item(item: ast.Item, depth = 0): string {
|
||||
public item(item: ast.Item, d = 0): string {
|
||||
const ident = item.ident.text;
|
||||
const pub = item.pub ? "pub " : "";
|
||||
const k = item.kind;
|
||||
@ -51,11 +51,9 @@ export class HirStringifyer {
|
||||
case "error":
|
||||
return "<error>;";
|
||||
case "mod_block":
|
||||
return `${pub}mod ${ident} ${this.block(k.block, depth)}`;
|
||||
return `${pub}mod ${ident} ${this.block(k.block, d)}`;
|
||||
case "mod_file":
|
||||
return `${pub}mod ${ident} {\n${
|
||||
this.file(k.ast!, depth + 1)
|
||||
}\n}`;
|
||||
return `${pub}mod ${ident} {\n${this.file(k.ast!, d + 1)}\n}`;
|
||||
case "enum":
|
||||
return `enum ${ident}: ${
|
||||
this.ty(this.ch.enumItemTy(item, k))
|
||||
@ -70,11 +68,11 @@ export class HirStringifyer {
|
||||
throw new Error();
|
||||
}
|
||||
const params = k.params
|
||||
.map((param) => this.pat(param.pat))
|
||||
.map((param) => this.pat(param.pat, d))
|
||||
.join(", ");
|
||||
return `${pub}fn ${ident}(${params}) -> ${
|
||||
this.ty(ty.kind.returnTy)
|
||||
} ${this.block(k.body!, depth)}`;
|
||||
} ${this.block(k.body!, d)}`;
|
||||
}
|
||||
case "use":
|
||||
return todo();
|
||||
@ -137,6 +135,17 @@ export class HirStringifyer {
|
||||
return `if ${this.expr(k.cond, d)} ${this.expr(k.truthy, d)}${
|
||||
k.falsy && ` else ${this.expr(k.falsy, d)}` || ""
|
||||
}`;
|
||||
case "match":
|
||||
return `match ${this.expr(k.expr, d)} ${
|
||||
k.arms.length === 0
|
||||
? "{}"
|
||||
: `{${
|
||||
k.arms.map((arm) => this.matchArm(arm, d + 1)).map(
|
||||
(s) =>
|
||||
`\n${s},`,
|
||||
)
|
||||
}\n${indent(d)}}`
|
||||
}`;
|
||||
case "loop":
|
||||
return `loop ${this.expr(k.body, d)}`;
|
||||
case "while":
|
||||
@ -153,7 +162,11 @@ export class HirStringifyer {
|
||||
exhausted(k);
|
||||
}
|
||||
|
||||
public pat(pat: ast.Pat): string {
|
||||
public matchArm(arm: ast.MatchArm, d: number): string {
|
||||
return `${this.pat(arm.pat, d)} => ${this.expr(arm.expr, d + 1)}`;
|
||||
}
|
||||
|
||||
public pat(pat: ast.Pat, d: number): string {
|
||||
const k = pat.kind;
|
||||
switch (k.tag) {
|
||||
case "error":
|
||||
@ -163,7 +176,23 @@ export class HirStringifyer {
|
||||
this.ty(this.ch.patTy(pat))
|
||||
}`;
|
||||
case "path":
|
||||
return todo();
|
||||
return this.path(k.path);
|
||||
case "tuple":
|
||||
return `${k.path && this.path(k.path) || ""}(${
|
||||
k.elems.map((pat) => this.pat(pat, d)).join(", ")
|
||||
})`;
|
||||
case "struct":
|
||||
return `${k.path ? `${this.path(k.path)}` : "struct "} {${
|
||||
[
|
||||
k.fields
|
||||
.map((field) =>
|
||||
`${indent(d + 1)}${field.ident.text}: ${
|
||||
this.pat(field.pat, d + 1)
|
||||
},`
|
||||
)
|
||||
.join("\n"),
|
||||
].map((s) => `\n${s}\n${indent(d)}`)
|
||||
}}`;
|
||||
}
|
||||
exhausted(k);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user