Compare commits
No commits in common. "696bfc55f40008c9f1e822879d1d6d5463aaf3e6" and "086bea3e89dea3d2d19ad64058e9cf20706e4540" have entirely different histories.
696bfc55f4
...
086bea3e89
10
src/ast.ts
10
src/ast.ts
@ -174,7 +174,7 @@ export type IntTy =
|
|||||||
|
|
||||||
export type UnaryOp =
|
export type UnaryOp =
|
||||||
| "Not"
|
| "Not"
|
||||||
| "Neg"
|
| "Negate"
|
||||||
| "Ref"
|
| "Ref"
|
||||||
| "RefMut"
|
| "RefMut"
|
||||||
| "Deref";
|
| "Deref";
|
||||||
@ -194,10 +194,10 @@ export type BinaryOp =
|
|||||||
| "Shl"
|
| "Shl"
|
||||||
| "Shr"
|
| "Shr"
|
||||||
| "Add"
|
| "Add"
|
||||||
| "Sub"
|
| "Subtract"
|
||||||
| "Mul"
|
| "Multiply"
|
||||||
| "Div"
|
| "Divide"
|
||||||
| "Rem";
|
| "Remainder";
|
||||||
|
|
||||||
export type RangeLimit = "Inclusive" | "Exclusive";
|
export type RangeLimit = "Inclusive" | "Exclusive";
|
||||||
|
|
||||||
|
|||||||
@ -205,9 +205,7 @@ class ExprChecker {
|
|||||||
case "IntExpr":
|
case "IntExpr":
|
||||||
return this.checkIntExpr(node.as(tag));
|
return this.checkIntExpr(node.as(tag));
|
||||||
case "StrExpr":
|
case "StrExpr":
|
||||||
return Ty.create("Ptr", {
|
return Ty.create("Ptr", { ty: Ty.Str });
|
||||||
ty: Ty.create("Slice", { ty: Ty.U8 }),
|
|
||||||
});
|
|
||||||
case "ArrayExpr":
|
case "ArrayExpr":
|
||||||
return this.checkArrayExpr(node.as(tag));
|
return this.checkArrayExpr(node.as(tag));
|
||||||
case "IndexExpr":
|
case "IndexExpr":
|
||||||
@ -302,6 +300,12 @@ class ExprChecker {
|
|||||||
) {
|
) {
|
||||||
return Ty.create("Slice", { ty: exprTy.kind.ty });
|
return Ty.create("Slice", { ty: exprTy.kind.ty });
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
exprTy.is("Str") &&
|
||||||
|
argTy.compatibleWith(Ty.I32)
|
||||||
|
) {
|
||||||
|
return Ty.I32;
|
||||||
|
}
|
||||||
this.cx.error(
|
this.cx.error(
|
||||||
node.loc,
|
node.loc,
|
||||||
`cannot use index operator on '${exprTy.pretty()}' with '${argTy.pretty()}'`,
|
`cannot use index operator on '${exprTy.pretty()}' with '${argTy.pretty()}'`,
|
||||||
@ -382,7 +386,8 @@ class ExprChecker {
|
|||||||
!(argTy.is("Array") ||
|
!(argTy.is("Array") ||
|
||||||
argTy.is("Ptr") &&
|
argTy.is("Ptr") &&
|
||||||
(argTy.kind.ty.is("Array") ||
|
(argTy.kind.ty.is("Array") ||
|
||||||
argTy.kind.ty.is("Slice")))
|
argTy.kind.ty.is("Slice") ||
|
||||||
|
argTy.kind.ty.is("Str")))
|
||||||
) {
|
) {
|
||||||
this.reportArgTypeNotCompatible(
|
this.reportArgTypeNotCompatible(
|
||||||
node,
|
node,
|
||||||
@ -404,7 +409,7 @@ class ExprChecker {
|
|||||||
|
|
||||||
private checkUnaryExpr(node: ast.NodeWithKind<"UnaryExpr">): Ty {
|
private checkUnaryExpr(node: ast.NodeWithKind<"UnaryExpr">): Ty {
|
||||||
const exprTy = this.cx.expr(node.kind.expr);
|
const exprTy = this.cx.expr(node.kind.expr);
|
||||||
if (node.kind.op === "Neg" && exprTy.compatibleWith(Ty.I32)) {
|
if (node.kind.op === "Negate" && exprTy.compatibleWith(Ty.I32)) {
|
||||||
return Ty.I32;
|
return Ty.I32;
|
||||||
}
|
}
|
||||||
if (node.kind.op === "Not" && exprTy.compatibleWith(Ty.Bool)) {
|
if (node.kind.op === "Not" && exprTy.compatibleWith(Ty.Bool)) {
|
||||||
@ -525,6 +530,8 @@ class TyChecker {
|
|||||||
return Ty.Void;
|
return Ty.Void;
|
||||||
case "bool":
|
case "bool":
|
||||||
return Ty.Bool;
|
return Ty.Bool;
|
||||||
|
case "str":
|
||||||
|
return Ty.Str;
|
||||||
case "i8":
|
case "i8":
|
||||||
return Ty.I8;
|
return Ty.I8;
|
||||||
case "i16":
|
case "i16":
|
||||||
@ -598,13 +605,7 @@ type BinaryOpTest = (op: ast.BinaryOp, left: Ty, right: Ty) => Ty | null;
|
|||||||
|
|
||||||
const binaryOpTests: BinaryOpTest[] = [
|
const binaryOpTests: BinaryOpTest[] = [
|
||||||
(op, left, right) => {
|
(op, left, right) => {
|
||||||
const ops: ast.BinaryOp[] = [
|
const ops = ["Add", "Subtract", "Multiply", "Divide", "Remainder"];
|
||||||
"Add",
|
|
||||||
"Sub",
|
|
||||||
"Mul",
|
|
||||||
"Div",
|
|
||||||
"Rem",
|
|
||||||
];
|
|
||||||
if (
|
if (
|
||||||
ops.includes(op) && left.is("Int") && left.compatibleWith(right)
|
ops.includes(op) && left.is("Int") && left.compatibleWith(right)
|
||||||
) {
|
) {
|
||||||
@ -613,7 +614,7 @@ const binaryOpTests: BinaryOpTest[] = [
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
(op, left, right) => {
|
(op, left, right) => {
|
||||||
const ops: ast.BinaryOp[] = ["Eq", "Ne", "Lt", "Gt", "Lte", "Gte"];
|
const ops = ["Eq", "Ne", "Lt", "Gt", "Lte", "Gte"];
|
||||||
if (
|
if (
|
||||||
ops.includes(op) && left.is("Int") && left.compatibleWith(right)
|
ops.includes(op) && left.is("Int") && left.compatibleWith(right)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -197,10 +197,10 @@ export class Parser {
|
|||||||
["<<", "Shl", 3],
|
["<<", "Shl", 3],
|
||||||
[">>", "Shr", 3],
|
[">>", "Shr", 3],
|
||||||
["+", "Add", 2],
|
["+", "Add", 2],
|
||||||
["-", "Sub", 2],
|
["-", "Subtract", 2],
|
||||||
["*", "Mul", 1],
|
["*", "Multiply", 1],
|
||||||
["/", "Div", 1],
|
["/", "Divide", 1],
|
||||||
["%", "Rem", 1],
|
["%", "Remainder", 1],
|
||||||
];
|
];
|
||||||
|
|
||||||
let left = this.parseBinary(prec - 1);
|
let left = this.parseBinary(prec - 1);
|
||||||
@ -228,7 +228,7 @@ export class Parser {
|
|||||||
const loc = this.loc();
|
const loc = this.loc();
|
||||||
const ops: [Tok["type"], ast.UnaryOp][] = [
|
const ops: [Tok["type"], ast.UnaryOp][] = [
|
||||||
["not", "Not"],
|
["not", "Not"],
|
||||||
["-", "Neg"],
|
["-", "Negate"],
|
||||||
["*", "Deref"],
|
["*", "Deref"],
|
||||||
];
|
];
|
||||||
for (const [tok, op] of ops) {
|
for (const [tok, op] of ops) {
|
||||||
|
|||||||
@ -248,6 +248,17 @@ class FnLowerer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (valueTy.is("Str")) {
|
||||||
|
const valueInst = this.lowerPlace(place.kind.value);
|
||||||
|
if (argTy.is("Int")) {
|
||||||
|
const argInst = this.lowerExpr(arg);
|
||||||
|
return this.pushInst(
|
||||||
|
Ty.create("Ptr", { ty: Ty.I32 }),
|
||||||
|
"GetElemPtr",
|
||||||
|
{ base: valueInst, offset: argInst },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${place.kind.tag} with arg ${argTy.pretty()} not handled`,
|
`${place.kind.tag} with arg ${argTy.pretty()} not handled`,
|
||||||
);
|
);
|
||||||
@ -345,7 +356,7 @@ class FnLowerer {
|
|||||||
const resultTy = this.tys.expr(expr);
|
const resultTy = this.tys.expr(expr);
|
||||||
const operandTy = this.tys.expr(expr.kind.expr);
|
const operandTy = this.tys.expr(expr.kind.expr);
|
||||||
if (
|
if (
|
||||||
expr.kind.op === "Neg" &&
|
expr.kind.op === "Negate" &&
|
||||||
operandTy.compatibleWith(Ty.I32) &&
|
operandTy.compatibleWith(Ty.I32) &&
|
||||||
resultTy.compatibleWith(Ty.I32)
|
resultTy.compatibleWith(Ty.I32)
|
||||||
) {
|
) {
|
||||||
@ -424,14 +435,21 @@ type BinaryOpTest = (
|
|||||||
|
|
||||||
const binaryOpTests: BinaryOpTest[] = [
|
const binaryOpTests: BinaryOpTest[] = [
|
||||||
(op, left, right, result) => {
|
(op, left, right, result) => {
|
||||||
const ops: ast.BinaryOp[] = ["Add", "Sub", "Mul", "Div", "Rem"];
|
const ops = ["Add", "Subtract", "Multiply", "Divide", "Remainder"];
|
||||||
|
const tags: Record<string, BinaryOp> = {
|
||||||
|
"Add": "Add",
|
||||||
|
"Subtract": "Sub",
|
||||||
|
"Multiply": "Mul",
|
||||||
|
"Divide": "Div",
|
||||||
|
"Remainder": "Rem",
|
||||||
|
};
|
||||||
if (
|
if (
|
||||||
ops.includes(op) &&
|
ops.includes(op) &&
|
||||||
left.is("Int") &&
|
left.is("Int") &&
|
||||||
left.compatibleWith(right) &&
|
left.compatibleWith(right) &&
|
||||||
result.compatibleWith(left)
|
result.compatibleWith(left)
|
||||||
) {
|
) {
|
||||||
return op as BinaryOp;
|
return tags[op];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -199,13 +199,12 @@ export type InstKind =
|
|||||||
| { tag: "Jump"; target: BasicBlock }
|
| { tag: "Jump"; target: BasicBlock }
|
||||||
| { tag: "Branch"; cond: Inst; truthy: BasicBlock; falsy: BasicBlock }
|
| { tag: "Branch"; cond: Inst; truthy: BasicBlock; falsy: BasicBlock }
|
||||||
| { tag: "Return"; source: Inst }
|
| { tag: "Return"; source: Inst }
|
||||||
| { tag: UnaryOp; source: Inst }
|
| { tag: "Not"; source: Inst }
|
||||||
|
| { tag: "Negate"; source: Inst }
|
||||||
| { tag: BinaryOp; left: Inst; right: Inst }
|
| { tag: BinaryOp; left: Inst; right: Inst }
|
||||||
| { tag: "Len"; source: Inst }
|
| { tag: "Len"; source: Inst }
|
||||||
| { tag: "DebugPrint"; args: Inst[] };
|
| { tag: "DebugPrint"; args: Inst[] };
|
||||||
|
|
||||||
export type UnaryOp = "Not" | "Negate";
|
|
||||||
|
|
||||||
export type BinaryOp =
|
export type BinaryOp =
|
||||||
| "Eq"
|
| "Eq"
|
||||||
| "Ne"
|
| "Ne"
|
||||||
|
|||||||
@ -35,6 +35,7 @@ export class Ty {
|
|||||||
static U64 = Ty.create("Int", { intTy: "u64" });
|
static U64 = Ty.create("Int", { intTy: "u64" });
|
||||||
static USize = Ty.create("Int", { intTy: "usize" });
|
static USize = Ty.create("Int", { intTy: "usize" });
|
||||||
static Bool = Ty.create("Bool", {});
|
static Bool = Ty.create("Bool", {});
|
||||||
|
static Str = Ty.create("Str", {});
|
||||||
|
|
||||||
private internHash(): string {
|
private internHash(): string {
|
||||||
return JSON.stringify(this.kind);
|
return JSON.stringify(this.kind);
|
||||||
@ -74,6 +75,9 @@ export class Ty {
|
|||||||
if (this.is("Bool")) {
|
if (this.is("Bool")) {
|
||||||
return other.is("Bool");
|
return other.is("Bool");
|
||||||
}
|
}
|
||||||
|
if (this.is("Str")) {
|
||||||
|
return other.is("Str");
|
||||||
|
}
|
||||||
if (this.is("Ptr")) {
|
if (this.is("Ptr")) {
|
||||||
if (!other.is("Ptr")) {
|
if (!other.is("Ptr")) {
|
||||||
return false;
|
return false;
|
||||||
@ -138,7 +142,7 @@ export class Ty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isSized(): boolean {
|
isSized(): boolean {
|
||||||
if (this.is("Slice")) {
|
if (this.is("Slice") || this.is("Str")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -156,6 +160,8 @@ export class Ty {
|
|||||||
return `${this.kind.intTy}`;
|
return `${this.kind.intTy}`;
|
||||||
case "Bool":
|
case "Bool":
|
||||||
return "bool";
|
return "bool";
|
||||||
|
case "Str":
|
||||||
|
return "str";
|
||||||
case "Ptr":
|
case "Ptr":
|
||||||
return `*${this.kind.ty.pretty()}`;
|
return `*${this.kind.ty.pretty()}`;
|
||||||
case "PtrMut":
|
case "PtrMut":
|
||||||
@ -193,6 +199,7 @@ export type TyKind =
|
|||||||
| { tag: "IntLiteral" }
|
| { tag: "IntLiteral" }
|
||||||
| { tag: "Int"; intTy: ast.IntTy }
|
| { tag: "Int"; intTy: ast.IntTy }
|
||||||
| { tag: "Bool" }
|
| { tag: "Bool" }
|
||||||
|
| { tag: "Str" }
|
||||||
| { tag: "Ptr"; ty: Ty }
|
| { tag: "Ptr"; ty: Ty }
|
||||||
| { tag: "PtrMut"; ty: Ty }
|
| { tag: "PtrMut"; ty: Ty }
|
||||||
| { tag: "Array"; ty: Ty; length: number }
|
| { tag: "Array"; ty: Ty; length: number }
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
let my_string: *[u8] = "hello world";
|
let my_string: *str = "hello world";
|
||||||
// expect: hello world
|
// expect: hello world
|
||||||
print(my_string);
|
print(my_string);
|
||||||
// expect: 104
|
// expect: 104
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user