diff --git a/slige/compiler/ast/ast.ts b/slige/compiler/ast/ast.ts index 74cd281..a50901a 100644 --- a/slige/compiler/ast/ast.ts +++ b/slige/compiler/ast/ast.ts @@ -222,11 +222,13 @@ export type PatKind = | { tag: "error" } | { tag: "bind" } & BindPat | { tag: "path" } & PathPat + | { tag: "bool" } & BoolPat | { tag: "tuple" } & TuplePat | { tag: "struct" } & StructPat; export type BindPat = { ident: Ident; mut: boolean }; export type PathPat = { qty?: Ty; path: Path }; +export type BoolPat = { value: boolean }; export type TuplePat = { path?: Path; elems: Pat[] }; export type StructPat = { path?: Path; fields: PatField[] }; diff --git a/slige/compiler/ast/visitor.ts b/slige/compiler/ast/visitor.ts index af4d371..0d4f583 100644 --- a/slige/compiler/ast/visitor.ts +++ b/slige/compiler/ast/visitor.ts @@ -10,6 +10,7 @@ import { Block, BlockExpr, BoolExpr, + BoolPat, BreakStmt, CallExpr, CForExpr, @@ -132,6 +133,7 @@ export interface Visitor< visitErrorPat?(pat: Pat, ...p: P): R; visitBindPat?(pat: Pat, kind: BindPat, ...p: P): R; visitPathPat?(pat: Pat, kind: PathPat, ...p: P): R; + visitBoolPat?(pat: Pat, kind: BoolPat, ...p: P): R; visitTuplePat?(pat: Pat, kind: TuplePat, ...p: P): R; visitStructPat?(pat: Pat, kind: StructPat, ...p: P): R; @@ -532,6 +534,9 @@ export function visitPat< if (v.visitPathPat?.(pat, kind, ...p) === "stop") return; visitPath(v, kind.path, ...p); return; + case "bool": + if (v.visitBoolPat?.(pat, kind, ...p) === "stop") return; + return; case "tuple": if (v.visitTuplePat?.(pat, kind, ...p) === "stop") return; kind.path && visitPath(v, kind.path, ...p); diff --git a/slige/compiler/check/checker.ts b/slige/compiler/check/checker.ts index 303c98d..b79046c 100644 --- a/slige/compiler/check/checker.ts +++ b/slige/compiler/check/checker.ts @@ -91,6 +91,8 @@ export class Checker { return Ok(undefined); case "path": return todo(); + case "bool": + return Ok(undefined); case "tuple": { if (k.path) { const re = this.re.pathRes(k.path.id); @@ -133,6 +135,35 @@ export class Checker { } return Res.Ok(undefined); } + if (re.kind.tag === "struct") { + const data = re.kind.kind.data; + if ( + data.kind.tag !== "tuple" || + ty.kind.tag !== "struct" || + ty.kind.data.tag !== "tuple" + ) { + return Res.Err({ + msg: "type/pattern mismatch", + span: pat.span, + }); + } + if (k.elems.length !== data.kind.elems.length) { + return Res.Err({ + msg: `incorrect amount of elements, expected ${data.kind.elems.length} got ${k.elems.length}`, + span: pat.span, + }); + } + for (const i of data.kind.elems.keys()) { + const res = this.assignPatTy( + k.elems[i], + ty.kind.data.elems[i].ty, + ); + if (!res.ok) { + return res; + } + } + return Res.Ok(undefined); + } } return todo(); } @@ -995,6 +1026,7 @@ export class Checker { case "int": return Ty({ tag: "int" }); case "bool": + return Ty({ tag: "bool" }); case "str": return todo(k.tag); case "path": { @@ -1073,6 +1105,10 @@ export class Checker { return todo(); } case "path": + return todo(); + case "bool": { + return this.patTy(pat); + } case "tuple": case "struct": return todo(); diff --git a/slige/compiler/middle/ast_lower.ts b/slige/compiler/middle/ast_lower.ts index d69efbe..31373ce 100644 --- a/slige/compiler/middle/ast_lower.ts +++ b/slige/compiler/middle/ast_lower.ts @@ -164,6 +164,9 @@ export class FnLowerer { return; } case "path": + return todo(); + case "bool": + return; case "tuple": case "struct": return todo(); @@ -186,6 +189,9 @@ export class FnLowerer { return; } case "path": + return todo(); + case "bool": + return; case "tuple": case "struct": return todo(); @@ -569,6 +575,7 @@ export class FnLowerer { nextArmBlock, ); this.pushCreatedBlock(exprBlock); + this.lowerMatchArmPatternBindings(discr, arm.pat); const rval = this.lowerExpr(arm.expr); this.addStmt({ tag: "assign", @@ -588,6 +595,102 @@ export class FnLowerer { pat: ast.Pat, truthyBlock: Block, falsyBlock: Block, + ) { + const discrOperand = this.lowerMatchArmPatternCondition(discr, pat); + this.setTer({ + tag: "switch", + discr: discrOperand, + targets: [{ value: 1, target: truthyBlock.id }], + otherwise: falsyBlock.id, + }); + } + + private lowerMatchArmPatternCondition( + discr: RVal, + pat: ast.Pat, + ): Operand { + const k = pat.kind; + switch (k.tag) { + case "error": + return { tag: "error" }; + case "bind": { + return { tag: "const", val: { tag: "int", value: 1 } }; + } + case "path": + return todo(); + case "bool": { + const ty = this.ch.patTy(pat); + if (ty.kind.tag !== "bool") { + throw new Error(); + } + const discrLocal = this.local(ty); + this.addStmt({ + tag: "assign", + place: { local: discrLocal, proj: [] }, + rval: discr, + }); + const local = this.local(ty); + this.addStmt({ + tag: "assign", + place: { local, proj: [] }, + rval: { + tag: "binary", + binaryType: "eq", + left: this.copyOrMoveLocal(discrLocal, ty), + right: { tag: "const", val: { tag: "int", value: 1 } }, + }, + }); + return this.copyOrMoveLocal(local, ty); + } + case "tuple": { + const ty = this.ch.patTy(pat); + if (ty.kind.tag === "struct") { + const discrLocal = this.local(ty); + this.addStmt({ + tag: "assign", + place: { local: discrLocal, proj: [] }, + rval: discr, + }); + const condLocals: LocalId[] = []; + for (const [fieldIdx, pat] of k.elems.entries()) { + if (ty.kind.data.tag !== "tuple") { + throw new Error(); + } + const elemTy = ty.kind.data.elems[fieldIdx].ty; + const condOperand = this.lowerMatchArmPatternCondition({ + tag: "use", + operand: { + tag: "move", + place: { + local: discrLocal, + proj: [{ tag: "field", fieldIdx }], + }, + }, + }, pat); + const condLocal = this.local(Ty({ tag: "int" })); + this.addStmt({ + tag: "assign", + place: { local: condLocal, proj: [] }, + rval: { tag: "use", operand: condOperand }, + }); + condLocals.push(condLocal); + } + const condRVal = condLocals + .reduce((condRVal, condLocal) => { + const local = this.local(Ty({ tag: "int" })); + }); + } + return todo(); + } + case "struct": + return todo(); + } + exhausted(k); + } + + private lowerMatchArmPatternBindings( + discr: RVal, + pat: ast.Pat, ) { const k = pat.kind; switch (k.tag) { @@ -601,14 +704,14 @@ export class FnLowerer { place: { local, proj: [] }, rval: discr, }); - this.setTer({ tag: "goto", target: truthyBlock.id }); return; } case "path": + return; + case "bool": + return; + case "tuple": return todo(); - case "tuple": { - return todo(); - } case "struct": return todo(); } diff --git a/slige/compiler/parse/parser.ts b/slige/compiler/parse/parser.ts index e30fc10..d2986ff 100644 --- a/slige/compiler/parse/parser.ts +++ b/slige/compiler/parse/parser.ts @@ -1222,6 +1222,14 @@ export class Parser { const ident = this.parseIdent(); return this.pat({ tag: "bind", ident, mut: true }, begin); } + if (this.test("false")) { + this.step(); + return this.pat({ tag: "bool", value: false }, begin); + } + if (this.test("true")) { + this.step(); + return this.pat({ tag: "bool", value: true }, begin); + } this.report(`expected pattern, got '${this.current().type}'`, begin); this.step(); return this.pat({ tag: "error" }, begin); diff --git a/slige/compiler/program.slg b/slige/compiler/program.slg index 7905a9b..9105166 100644 --- a/slige/compiler/program.slg +++ b/slige/compiler/program.slg @@ -2,14 +2,25 @@ // #[builtin(Hello)] // fn c_hello() -> int {} -fn main() { - let mut a = 2; - if true { - a = 3; - } else { +struct A(bool, bool); +fn main() { + //let mut a = 2; + //if true { + // a = 3; + //} else { + // + //} + //let b = a; + + let a = A(true, false); + + match a { + A(false, false) => {} + A(false, true) => {} + A(true, false) => {} + A(true, true) => {} } - let b = a; } diff --git a/slige/compiler/stringify/hir.ts b/slige/compiler/stringify/hir.ts index 836267c..3a584e7 100644 --- a/slige/compiler/stringify/hir.ts +++ b/slige/compiler/stringify/hir.ts @@ -180,6 +180,8 @@ export class HirStringifyer { }`; case "path": return this.path(k.path); + case "bool": + return k.value ? "true" : "false"; case "tuple": return `${k.path && this.path(k.path) || ""}(${ k.elems.map((pat) => this.pat(pat, d)).join(", ")