mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-14 16:35:03 +01:00
Add assignments
This commit is contained in:
parent
6d2a2fe474
commit
0bf9aed35e
6 changed files with 113 additions and 32 deletions
19
src/ast.ts
19
src/ast.ts
|
|
@ -72,9 +72,18 @@ export type ExprLet = {
|
|||
type?: Type;
|
||||
rhs: Expr;
|
||||
// IMPORTANT: This is (sadly) shared with ExprBlock.
|
||||
// TODO: Stop this sharing and just store the stack of blocks in typeck.
|
||||
local?: LocalInfo;
|
||||
};
|
||||
|
||||
// A bit like ExprBinary except there are restrictions
|
||||
// on the LHS and precedence is unrestricted.
|
||||
export type ExprAssign = {
|
||||
kind: "assign";
|
||||
lhs: Expr;
|
||||
rhs: Expr;
|
||||
};
|
||||
|
||||
export type ExprBlock = {
|
||||
kind: "block";
|
||||
exprs: Expr[];
|
||||
|
|
@ -128,6 +137,7 @@ export type ExprBreak = {
|
|||
/**
|
||||
* The break target block.
|
||||
* May be any control flow block, labelled from inside out.
|
||||
* TODO: This is not a good solution at all and pretty broken.
|
||||
*/
|
||||
target?: number;
|
||||
};
|
||||
|
|
@ -141,6 +151,7 @@ export type ExprStructLiteral = {
|
|||
export type ExprKind =
|
||||
| ExprEmpty
|
||||
| ExprLet
|
||||
| ExprAssign
|
||||
| ExprBlock
|
||||
| ExprLiteral
|
||||
| ExprIdent
|
||||
|
|
@ -482,6 +493,14 @@ export function superFoldExpr(expr: Expr, folder: Folder): Expr {
|
|||
rhs: folder.expr(expr.rhs),
|
||||
};
|
||||
}
|
||||
case "assign": {
|
||||
return {
|
||||
...expr,
|
||||
kind: "assign",
|
||||
lhs: folder.expr(expr.lhs),
|
||||
rhs: folder.expr(expr.rhs),
|
||||
};
|
||||
}
|
||||
case "block": {
|
||||
return {
|
||||
...expr,
|
||||
|
|
|
|||
32
src/index.ts
32
src/index.ts
|
|
@ -10,32 +10,14 @@ import fs from "fs";
|
|||
import { exec } from "child_process";
|
||||
|
||||
const input = `
|
||||
import("wasi_snapshot_preview1" "fd_write")
|
||||
fd_write(a: I32, b: I32, c: I32, d: I32): I32;
|
||||
|
||||
function coolerPrint(a: String) = (
|
||||
let ptr = __string_ptr(a);
|
||||
let len = __string_len(a);
|
||||
|
||||
let mem = 1024_I32;
|
||||
|
||||
__i32_store(mem + 4_I32, ptr);
|
||||
__i32_store(mem + 8_I32, 2_I32);
|
||||
|
||||
fd_write(
|
||||
// stdout
|
||||
1_I32,
|
||||
// iovec
|
||||
mem + 4_I32,
|
||||
// len
|
||||
len,
|
||||
// return value
|
||||
mem,
|
||||
);
|
||||
);
|
||||
|
||||
function main() = (
|
||||
coolerPrint("uwu\\n");
|
||||
let i = 0;
|
||||
loop (
|
||||
if i > 10 then break;
|
||||
|
||||
print("uwu\\n");
|
||||
i = i + 1;
|
||||
);
|
||||
);
|
||||
`;
|
||||
|
||||
|
|
|
|||
39
src/lower.ts
39
src/lower.ts
|
|
@ -272,6 +272,36 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
|
|||
|
||||
break;
|
||||
}
|
||||
case "assign": {
|
||||
lowerExpr(fcx, instrs, expr.rhs);
|
||||
const { lhs } = expr;
|
||||
switch (lhs.kind) {
|
||||
case "ident": {
|
||||
const res = lhs.value.res!;
|
||||
|
||||
switch (res.kind) {
|
||||
case "local": {
|
||||
const location =
|
||||
fcx.varLocations[fcx.varLocations.length - 1 - res.index];
|
||||
storeVariable(instrs, location);
|
||||
break;
|
||||
}
|
||||
case "item": {
|
||||
throw new Error("cannot store to item");
|
||||
}
|
||||
case "builtin": {
|
||||
throw new Error("cannot store to builtin");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error("invalid lhs side of assignment");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "block": {
|
||||
const prevVarLocationLengths = fcx.varLocations.length;
|
||||
|
||||
|
|
@ -610,6 +640,15 @@ function loadVariable(instrs: wasm.Instr[], loc: VarLocation) {
|
|||
});
|
||||
}
|
||||
|
||||
function storeVariable(instrs: wasm.Instr[], loc: VarLocation) {
|
||||
// Stores are just like loads, just the other way around.
|
||||
const types = loc.types.map((_, i) => i);
|
||||
types.reverse();
|
||||
types.forEach((i) => {
|
||||
instrs.push({ kind: "local.set", imm: loc.localIdx + i });
|
||||
});
|
||||
}
|
||||
|
||||
function computeAbi(ty: TyFn): FnAbi {
|
||||
function argRetAbi(param: Ty): ArgRetAbi {
|
||||
switch (param.kind) {
|
||||
|
|
|
|||
|
|
@ -174,13 +174,15 @@ function parseFunctionSig(t: Token[]): [Token[], FunctionSig] {
|
|||
|
||||
function parseExpr(t: Token[]): [Token[], Expr] {
|
||||
/*
|
||||
EXPR = COMPARISON
|
||||
EXPR = ASSIGNMENT
|
||||
|
||||
LET = "let" NAME { ":" TYPE } "=" EXPR "in" EXPR
|
||||
IF = "if" EXPR "then" EXPR { "else" EXPR }
|
||||
LOOP = "loop" EXPR
|
||||
BREAK = "break"
|
||||
|
||||
ASSIGNMENT = COMPARISON { "=" ASSIGNMENT }
|
||||
|
||||
// The precende here is pretty arbitrary since we forbid mixing of operators
|
||||
// with different precedence classes anyways.
|
||||
COMPARISON = LOGICAL { ( ">" | "<" | "==" | "<=" | ">=" | "!=" ) COMPARISON }
|
||||
|
|
@ -199,12 +201,17 @@ function parseExpr(t: Token[]): [Token[], Expr] {
|
|||
STRUCT_INIT = "{" { NAME ":" EXPR } { "," NAME ":" EXPR } { "," } "}"
|
||||
EXPR_LIST = { EXPR { "," EXPR } { "," } }
|
||||
*/
|
||||
return parseExprComparison(t);
|
||||
return parseExprAssignment(t);
|
||||
}
|
||||
|
||||
function mkBinaryExpr(lhs: Expr, rhs: Expr, span: Span, kind: string): Expr {
|
||||
return { kind: "binary", binaryKind: kind as BinaryKind, lhs, rhs, span };
|
||||
}
|
||||
|
||||
function mkParserExprBinary(
|
||||
lower: Parser<Expr>,
|
||||
kinds: string[]
|
||||
kinds: string[],
|
||||
mkExpr = mkBinaryExpr
|
||||
): Parser<Expr> {
|
||||
function parser(t: Token[]): [Token[], Expr] {
|
||||
let lhs;
|
||||
|
|
@ -216,10 +223,7 @@ function mkParserExprBinary(
|
|||
let rhs;
|
||||
[t, rhs] = parser(t);
|
||||
const span = spanMerge(lhs.span, rhs.span);
|
||||
return [
|
||||
t,
|
||||
{ kind: "binary", binaryKind: peek.kind as BinaryKind, lhs, rhs, span },
|
||||
];
|
||||
return [t, mkExpr(lhs, rhs, span, peek.kind)];
|
||||
}
|
||||
|
||||
return [t, lhs];
|
||||
|
|
@ -245,6 +249,12 @@ const parseExprComparison = mkParserExprBinary(
|
|||
COMPARISON_KINDS
|
||||
);
|
||||
|
||||
const parseExprAssignment = mkParserExprBinary(
|
||||
parseExprComparison,
|
||||
["="],
|
||||
(lhs, rhs, span) => ({ kind: "assign", lhs, rhs, span })
|
||||
);
|
||||
|
||||
function parseExprUnary(t: Token[]): [Token[], Expr] {
|
||||
const [, peak] = next(t);
|
||||
if (peak.kind in UNARY_KINDS) {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ function printExpr(expr: Expr, indent: number): string {
|
|||
indent + 1
|
||||
)}`;
|
||||
}
|
||||
case "assign": {
|
||||
return `${printExpr(expr.lhs, indent)} = ${printExpr(expr.rhs, indent)}`;
|
||||
}
|
||||
case "block": {
|
||||
const exprs = expr.exprs.map((expr) => printExpr(expr, indent + 1));
|
||||
|
||||
|
|
|
|||
|
|
@ -557,6 +557,34 @@ export function checkBody(
|
|||
span: expr.span,
|
||||
};
|
||||
}
|
||||
case "assign": {
|
||||
const lhs = this.expr(expr.lhs);
|
||||
const rhs = this.expr(expr.rhs);
|
||||
|
||||
infcx.assign(lhs.ty!, rhs.ty!, expr.span);
|
||||
|
||||
switch (lhs.kind) {
|
||||
case "ident":
|
||||
if (lhs.value.res!.kind !== "local") {
|
||||
throw new CompilerError("cannot assign to items", expr.span);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
throw new CompilerError(
|
||||
"invalid left-hand side of assignment",
|
||||
lhs.span
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...expr,
|
||||
kind: "assign",
|
||||
lhs,
|
||||
rhs,
|
||||
ty: TY_UNIT,
|
||||
};
|
||||
}
|
||||
case "block": {
|
||||
currentNestingDepth++;
|
||||
const prevLocalTysLen = localTys.length;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue