mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: types and strings
This commit is contained in:
parent
0b65a5841f
commit
f291516c87
@ -1,3 +1,4 @@
|
||||
import { AttrView } from "./attr.ts";
|
||||
import * as lir from "./lir.ts";
|
||||
|
||||
export class AsmGen {
|
||||
@ -34,40 +35,57 @@ export class AsmGen {
|
||||
}
|
||||
|
||||
private generateFn(fn: lir.Fn) {
|
||||
const query = this.queryCFunction(fn);
|
||||
if (query.found) {
|
||||
const { label, args } = query;
|
||||
const cFunctionQuery = this.queryCFunction(fn);
|
||||
if (cFunctionQuery.found) {
|
||||
const { label, args } = cFunctionQuery;
|
||||
this.generateCFunctionBody(fn, label, args);
|
||||
return;
|
||||
}
|
||||
|
||||
this.generateFnBody(fn);
|
||||
|
||||
const cExportQuery = this.queryCExport(fn);
|
||||
if (cExportQuery.found) {
|
||||
const { label } = cExportQuery;
|
||||
this.generateCExporter(fn, label);
|
||||
}
|
||||
}
|
||||
|
||||
private queryCFunction(
|
||||
fn: lir.Fn,
|
||||
): { found: false } | { found: true; label: string; args: number } {
|
||||
const stmtKind = fn.mir.stmt.kind;
|
||||
if (stmtKind.tag !== "fn") {
|
||||
throw new Error();
|
||||
}
|
||||
if (stmtKind.attrs.at(0)?.ident === "c_function") {
|
||||
const arg = stmtKind.attrs.at(0)!.args.at(0);
|
||||
if (!arg || arg.kind.tag !== "string") {
|
||||
const attrs = AttrView.fromStmt(fn.mir.stmt);
|
||||
if (attrs.has("c_function")) {
|
||||
const attr = attrs.get("c_function");
|
||||
if (attr.args !== 1 || !attr.isStr(0)) {
|
||||
throw new Error("incorrect args for attribute");
|
||||
}
|
||||
return {
|
||||
found: true,
|
||||
label: arg.kind.val,
|
||||
label: attr.strVal(0),
|
||||
args: fn.mir.paramLocals.size,
|
||||
};
|
||||
}
|
||||
return { found: false };
|
||||
}
|
||||
|
||||
private queryCExport(
|
||||
fn: lir.Fn,
|
||||
): { found: false } | { found: true; label: string } {
|
||||
const attrs = AttrView.fromStmt(fn.mir.stmt);
|
||||
if (attrs.has("c_export")) {
|
||||
const attr = attrs.get("c_export");
|
||||
if (attr.args !== 1 || !attr.isStr(0)) {
|
||||
throw new Error("incorrect args for attribute");
|
||||
}
|
||||
const label = attr.strVal(0);
|
||||
return { found: true, label };
|
||||
}
|
||||
return { found: false };
|
||||
}
|
||||
|
||||
private generateCFunctionBody(fn: lir.Fn, label: string, args: number) {
|
||||
this.writeln(`extern ${label}`);
|
||||
this.writeln(`global ${fn.label}`);
|
||||
this.writeln(`${fn.label}:`);
|
||||
|
||||
this.writeIns(`push rbp`);
|
||||
@ -90,7 +108,6 @@ export class AsmGen {
|
||||
}
|
||||
|
||||
private generateFnBody(fn: lir.Fn) {
|
||||
this.writeln(`global ${fn.label}:`);
|
||||
this.writeln(`${fn.label}:`);
|
||||
this.writeIns(`push rbp`);
|
||||
this.writeIns(`mov rbp, rsp`);
|
||||
@ -112,6 +129,28 @@ export class AsmGen {
|
||||
this.writeIns(`ret`);
|
||||
}
|
||||
|
||||
private generateCExporter(fn: lir.Fn, label: string) {
|
||||
this.writeln(`global ${label}`);
|
||||
this.writeln(`${label}:`);
|
||||
|
||||
this.writeIns(`push rbp`);
|
||||
this.writeIns(`mov rbp, rsp`);
|
||||
this.writeIns(`sub rsp, 8`);
|
||||
|
||||
const args = fn.mir.paramLocals.size;
|
||||
|
||||
const argRegs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||
for (const reg of argRegs.slice(0, args)) {
|
||||
this.writeIns(`push ${reg}`);
|
||||
}
|
||||
|
||||
this.writeIns(`call ${fn.label}`);
|
||||
|
||||
this.writeIns(`mov rsp, rbp`);
|
||||
this.writeIns(`pop rbp`);
|
||||
this.writeIns(`ret`);
|
||||
}
|
||||
|
||||
private generateIns(ins: lir.Ins) {
|
||||
const r = (reg: lir.Reg) => this.reg(reg);
|
||||
|
||||
|
@ -14,7 +14,7 @@ export type Stmt = {
|
||||
export type StmtKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "fn" } & FnStmt
|
||||
| { tag: "let"; ident: string; expr?: Expr }
|
||||
| { tag: "let" } & LetStmt
|
||||
| { tag: "loop"; body: Block }
|
||||
| { tag: "if"; expr: Expr; truthy: Block; falsy?: Block }
|
||||
| { tag: "return"; expr?: Expr }
|
||||
@ -25,10 +25,23 @@ export type StmtKind =
|
||||
export type FnStmt = {
|
||||
ident: string;
|
||||
attrs: Attr[];
|
||||
params: string[];
|
||||
params: Param[];
|
||||
returnTy: Ty;
|
||||
body: Block;
|
||||
};
|
||||
|
||||
export type LetStmt = {
|
||||
ident: string;
|
||||
ty?: Ty;
|
||||
expr?: Expr;
|
||||
};
|
||||
|
||||
export type Param = {
|
||||
ident: string;
|
||||
line: number;
|
||||
ty: Ty;
|
||||
};
|
||||
|
||||
export type Expr = {
|
||||
id: number;
|
||||
line: number;
|
||||
@ -39,12 +52,23 @@ export type ExprKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "ident"; ident: string }
|
||||
| { tag: "int"; val: number }
|
||||
| { tag: "string"; val: string }
|
||||
| { tag: "str"; val: string }
|
||||
| { tag: "call"; expr: Expr; args: Expr[] }
|
||||
| { tag: "binary"; op: BinaryOp; left: Expr; right: Expr };
|
||||
|
||||
export type BinaryOp = "<" | "==" | "+" | "*";
|
||||
|
||||
export type Ty = {
|
||||
id: number;
|
||||
line: number;
|
||||
kind: TyKind;
|
||||
};
|
||||
|
||||
export type TyKind =
|
||||
| { tag: "error" }
|
||||
| { tag: "ident"; ident: string }
|
||||
| { tag: "ptr"; ty: Ty };
|
||||
|
||||
export type Attr = {
|
||||
ident: string;
|
||||
args: Expr[];
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern int32_t sbc__main(void);
|
||||
extern int32_t sbc_main(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sbc__main();
|
||||
sbc_main();
|
||||
}
|
||||
|
@ -4,14 +4,18 @@ import {
|
||||
Block,
|
||||
Expr,
|
||||
ExprKind,
|
||||
Param,
|
||||
Stmt,
|
||||
StmtKind,
|
||||
Ty as AstTy,
|
||||
TyKind,
|
||||
} from "./ast.ts";
|
||||
import { Ty, tyToString } from "./ty.ts";
|
||||
|
||||
export class Checker {
|
||||
private stmtTys = new Map<number, Ty>();
|
||||
private exprTys = new Map<number, Ty>();
|
||||
private tyTys = new Map<number, Ty>();
|
||||
|
||||
public errorOccured = false;
|
||||
|
||||
@ -27,8 +31,9 @@ export class Checker {
|
||||
if (this.stmtTys.has(stmt.id)) {
|
||||
return this.stmtTys.get(stmt.id)!;
|
||||
}
|
||||
const params = k.params.map((_): Ty => ({ tag: "int" }));
|
||||
const returnTy: Ty = { tag: "int" };
|
||||
const params = k.params
|
||||
.map((param): Ty => this.tyTy(param.ty));
|
||||
const returnTy: Ty = this.tyTy(k.returnTy);
|
||||
const ty: Ty = { tag: "fn", stmt, params, returnTy };
|
||||
this.stmtTys.set(stmt.id, ty);
|
||||
return ty;
|
||||
@ -50,7 +55,30 @@ export class Checker {
|
||||
if (this.stmtTys.has(stmt.id)) {
|
||||
return this.stmtTys.get(stmt.id)!;
|
||||
}
|
||||
const ty: Ty = k.expr ? this.exprTy(k.expr) : { tag: "int" };
|
||||
const declTy = k.ty && this.tyTy(k.ty);
|
||||
const exprTy = k.expr && this.exprTy(k.expr);
|
||||
const tyRes = declTy && exprTy
|
||||
? this.resolveTys(declTy, exprTy)
|
||||
: declTy
|
||||
? { ok: true, ty: declTy } as const
|
||||
: exprTy
|
||||
? { ok: true, ty: exprTy } as const
|
||||
: { ok: true, ty: { tag: "unknown" } as Ty } as const;
|
||||
|
||||
if (!tyRes.ok) {
|
||||
this.report(tyRes.msg, stmt.line);
|
||||
const ty: Ty = { tag: "error" };
|
||||
this.stmtTys.set(stmt.id, ty);
|
||||
return ty;
|
||||
}
|
||||
const ty = tyRes.ty;
|
||||
if (ty.tag === "unknown") {
|
||||
this.report("could not infer type", stmt.line);
|
||||
const ty: Ty = { tag: "error" };
|
||||
this.stmtTys.set(stmt.id, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
this.stmtTys.set(stmt.id, ty);
|
||||
return ty;
|
||||
}
|
||||
@ -83,8 +111,8 @@ export class Checker {
|
||||
}
|
||||
case "int":
|
||||
return { tag: "int" };
|
||||
case "string":
|
||||
return { tag: "string" };
|
||||
case "str":
|
||||
return { tag: "ptr", ty: { tag: "str" } };
|
||||
case "call": {
|
||||
const callee = this.exprTy(k.expr);
|
||||
if (callee.tag !== "fn") {
|
||||
@ -98,13 +126,15 @@ export class Checker {
|
||||
);
|
||||
return { tag: "error" };
|
||||
}
|
||||
const args = k.args.map((arg) => this.exprTy(arg));
|
||||
|
||||
const argTys = k.args
|
||||
.map((arg) => this.exprTy(arg));
|
||||
for (const [i, param] of callee.params.entries()) {
|
||||
if (!this.assignable(args[i], param)) {
|
||||
console.log({ arg: argTys[i], param });
|
||||
const tyRes = this.resolveTys(argTys[i], param);
|
||||
if (!tyRes.ok) {
|
||||
this.report(
|
||||
`argument mismatch, type '${
|
||||
tyToString(args[i])
|
||||
}' not assignable to '${tyToString(param)}'`,
|
||||
`argument mismatch, ${tyRes.msg}`,
|
||||
expr.line,
|
||||
);
|
||||
}
|
||||
@ -147,6 +177,40 @@ export class Checker {
|
||||
return ty;
|
||||
}
|
||||
|
||||
public tyTy(astTy: AstTy): Ty {
|
||||
if (this.tyTys.has(astTy.id)) {
|
||||
return this.tyTys.get(astTy.id)!;
|
||||
}
|
||||
const ty = ((): Ty => {
|
||||
const k = astTy.kind;
|
||||
switch (k.tag) {
|
||||
case "error":
|
||||
return { tag: "error" };
|
||||
case "ident": {
|
||||
switch (k.ident) {
|
||||
case "int":
|
||||
return { tag: "int" };
|
||||
case "str":
|
||||
return { tag: "str" };
|
||||
default:
|
||||
this.report(
|
||||
`unknown type '${k.ident}'`,
|
||||
astTy.line,
|
||||
);
|
||||
return { tag: "error" };
|
||||
}
|
||||
}
|
||||
case "ptr": {
|
||||
const ty = this.tyTy(k.ty);
|
||||
return { tag: "ptr", ty };
|
||||
}
|
||||
}
|
||||
const _: never = k;
|
||||
})();
|
||||
this.tyTys.set(astTy.id, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
private assignable(a: Ty, b: Ty): boolean {
|
||||
if (a.tag !== b.tag) {
|
||||
return false;
|
||||
@ -157,16 +221,52 @@ export class Checker {
|
||||
return true;
|
||||
}
|
||||
|
||||
private resolveTys(a: Ty, b: Ty):
|
||||
| { ok: true; ty: Ty }
|
||||
| { ok: false; msg: string } {
|
||||
const ok = (ty: Ty) => ({ ok: true, ty } as const);
|
||||
const both = (tag: Ty["tag"]): boolean =>
|
||||
a.tag === tag && b.tag === tag;
|
||||
|
||||
if (a.tag === "error" || b.tag === "error") {
|
||||
return ok(a);
|
||||
} else if (both("int")) {
|
||||
return ok(a);
|
||||
} else if (both("str")) {
|
||||
return ok(a);
|
||||
} else if (
|
||||
a.tag === "ptr" && b.tag === "ptr"
|
||||
) {
|
||||
const tyRes = this.resolveTys(a.ty, b.ty);
|
||||
if (!tyRes.ok) {
|
||||
return tyRes;
|
||||
}
|
||||
return ok(a);
|
||||
} else if (
|
||||
a.tag === "fn" && b.tag === "fn" &&
|
||||
a.stmt.id !== b.stmt.id
|
||||
) {
|
||||
return ok(a);
|
||||
} else {
|
||||
return {
|
||||
ok: false,
|
||||
msg: `type '${tyToString(a)}' is not assignable to '${
|
||||
tyToString(b)
|
||||
}'`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private report(msg: string, line: number) {
|
||||
this.errorOccured = true;
|
||||
//console.error(`parser: ${msg} on line ${line}`);
|
||||
throw new Error(`parser: ${msg} on line ${line}`);
|
||||
//console.error(`Checker: ${msg} on line ${line}`);
|
||||
throw new Error(`Checker: ${msg} on line ${line}`);
|
||||
}
|
||||
}
|
||||
|
||||
export type Resolve =
|
||||
| { tag: "fn"; stmt: Stmt }
|
||||
| { tag: "param"; stmt: Stmt; i: number }
|
||||
| { tag: "param"; stmt: Stmt; param: Param; i: number }
|
||||
| { tag: "let"; stmt: Stmt }
|
||||
| { tag: "loop"; stmt: Stmt };
|
||||
|
||||
@ -298,7 +398,12 @@ export class Resolver {
|
||||
throw new Error();
|
||||
}
|
||||
for (const [i, param] of k.params.entries()) {
|
||||
this.syms.defineVal(param, { tag: "param", stmt: fn, i });
|
||||
this.syms.defineVal(param.ident, {
|
||||
tag: "param",
|
||||
stmt: fn,
|
||||
param,
|
||||
i,
|
||||
});
|
||||
}
|
||||
this.resolveBlock(k.body);
|
||||
|
||||
@ -375,7 +480,7 @@ export class Resolver {
|
||||
}
|
||||
case "int":
|
||||
return;
|
||||
case "string":
|
||||
case "str":
|
||||
return;
|
||||
case "call":
|
||||
this.resolveExpr(k.expr);
|
||||
@ -393,8 +498,8 @@ export class Resolver {
|
||||
|
||||
private report(msg: string, line: number) {
|
||||
this.errorOccured = true;
|
||||
//console.error(`parser: ${msg} on line ${line}`);
|
||||
throw new Error(`parser: ${msg} on line ${line}`);
|
||||
//console.error(`Resolver: ${msg} on line ${line}`);
|
||||
throw new Error(`Resolver: ${msg} on line ${line}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,6 +510,7 @@ export class Parser {
|
||||
private blockIds = 0;
|
||||
private stmtIds = 0;
|
||||
private exprIds = 0;
|
||||
private tyIds = 0;
|
||||
|
||||
private last: Tok;
|
||||
private eaten?: Tok;
|
||||
@ -534,13 +640,13 @@ export class Parser {
|
||||
this.report("expected '('");
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
const params: string[] = [];
|
||||
const params: Param[] = [];
|
||||
if (!this.done() && !this.test(")")) {
|
||||
if (!this.eat("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
const paramRes = this.parseParam();
|
||||
if (!paramRes.ok) {
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
params.push(this.eaten!.identVal!);
|
||||
params.push(paramRes.param);
|
||||
while (!this.done() && !this.test(")")) {
|
||||
if (!this.eat(",")) {
|
||||
this.report("expected ','");
|
||||
@ -549,23 +655,48 @@ export class Parser {
|
||||
if (this.test(")")) {
|
||||
break;
|
||||
}
|
||||
if (!this.eat("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
const paramRes = this.parseParam();
|
||||
if (!paramRes.ok) {
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
params.push(this.eaten!.identVal!);
|
||||
params.push(paramRes.param);
|
||||
}
|
||||
}
|
||||
if (!this.eat(")")) {
|
||||
this.report("expected ')'");
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
if (!this.eat("->")) {
|
||||
this.report("expected '->'");
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
const returnTy = this.parseTy();
|
||||
if (!this.test("{")) {
|
||||
this.report("expected block");
|
||||
return this.stmt({ tag: "error" }, line);
|
||||
}
|
||||
const body = this.parseBlock();
|
||||
return this.stmt({ tag: "fn", ident, attrs, params, body }, line);
|
||||
return this.stmt(
|
||||
{ tag: "fn", ident, attrs, params, returnTy, body },
|
||||
line,
|
||||
);
|
||||
}
|
||||
|
||||
private parseParam():
|
||||
| { ok: true; param: Param }
|
||||
| { ok: false } {
|
||||
const line = this.curr().line;
|
||||
if (!this.eat("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
return { ok: false };
|
||||
}
|
||||
const ident = this.eaten!.identVal!;
|
||||
if (!this.eat(":")) {
|
||||
this.report("expected ':'");
|
||||
return { ok: false };
|
||||
}
|
||||
const ty = this.parseTy();
|
||||
return { ok: true, param: { ident, line, ty } };
|
||||
}
|
||||
|
||||
private parseLetStmt(): Stmt {
|
||||
@ -722,17 +853,32 @@ export class Parser {
|
||||
{ tag: "int", val: this.eaten!.intVal! },
|
||||
this.eaten!.line,
|
||||
);
|
||||
} else if (this.eat("string")) {
|
||||
} else if (this.eat("str")) {
|
||||
return this.expr(
|
||||
{ tag: "string", val: this.eaten?.stringVal! },
|
||||
{ tag: "str", val: this.eaten?.stringVal! },
|
||||
this.eaten!.line,
|
||||
);
|
||||
} else {
|
||||
this.report("expected expr");
|
||||
this.report("expected expression");
|
||||
return this.expr({ tag: "error" }, this.last!.line);
|
||||
}
|
||||
}
|
||||
|
||||
private parseTy(): AstTy {
|
||||
if (this.eat("ident")) {
|
||||
return this.ty(
|
||||
{ tag: "ident", ident: this.eaten!.identVal! },
|
||||
this.eaten!.line,
|
||||
);
|
||||
} else if (this.eat("*")) {
|
||||
const ty = this.parseTy();
|
||||
return this.ty({ tag: "ptr", ty }, this.eaten!.line);
|
||||
} else {
|
||||
this.report("expected type");
|
||||
return this.ty({ tag: "error" }, this.last!.line);
|
||||
}
|
||||
}
|
||||
|
||||
private stmt(kind: StmtKind, line: number): Stmt {
|
||||
const id = this.stmtIds++;
|
||||
return { id, line, kind };
|
||||
@ -743,6 +889,11 @@ export class Parser {
|
||||
return { id, line, kind };
|
||||
}
|
||||
|
||||
private ty(kind: TyKind, line: number): AstTy {
|
||||
const id = this.tyIds++;
|
||||
return { id, line, kind };
|
||||
}
|
||||
|
||||
private eat(type: string): boolean {
|
||||
if (this.test(type)) {
|
||||
this.eaten = this.curr();
|
||||
@ -769,8 +920,8 @@ export class Parser {
|
||||
|
||||
private report(msg: string, line = this.last.line) {
|
||||
this.errorOccured = true;
|
||||
//console.error(`parser: ${msg} on line ${line}`);
|
||||
throw new Error(`parser: ${msg} on line ${line}`);
|
||||
//console.error(`Parser: ${msg} on line ${line}`);
|
||||
throw new Error(`Parser: ${msg} on line ${line}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -783,7 +934,7 @@ export type Tok = {
|
||||
};
|
||||
|
||||
export function lex(text: string): Tok[] {
|
||||
const ops = "(){}[]<>+*=,;#\n";
|
||||
const ops = "(){}[]<>+-*=:,;#\n";
|
||||
const kws = ["let", "fn", "return", "if", "else", "loop", "break"];
|
||||
|
||||
return ops
|
||||
@ -792,6 +943,7 @@ export function lex(text: string): Tok[] {
|
||||
text
|
||||
.replaceAll(/\/\/.*?$/mg, "")
|
||||
.replaceAll(op, ` ${op} `)
|
||||
.replaceAll(" - > ", " -> ")
|
||||
.replaceAll(" = = ", " == ")
|
||||
.replaceAll(/\\ /g, "\\SPACE"), text)
|
||||
.split(/[ \t\r]/)
|
||||
@ -814,7 +966,7 @@ export function lex(text: string): Tok[] {
|
||||
: { type: "ident", line, identVal: val };
|
||||
} else if (/^".*?"$/.test(val)) {
|
||||
return {
|
||||
type: "string",
|
||||
type: "str",
|
||||
line,
|
||||
stringVal: val
|
||||
.slice(1, val.length - 1)
|
||||
|
@ -1,6 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int64_t length;
|
||||
char data[];
|
||||
} Str;
|
||||
|
||||
int64_t notice(void)
|
||||
{
|
||||
printf("NOTICE!\n");
|
||||
@ -12,3 +17,9 @@ int64_t print_int(int64_t value)
|
||||
printf("%ld\n", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t println(const Str* value)
|
||||
{
|
||||
printf("%.*s\n", (int)value->length, value->data);
|
||||
return 0;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ class FnGen {
|
||||
return;
|
||||
case "push": {
|
||||
switch (k.val.tag) {
|
||||
case "string": {
|
||||
case "str": {
|
||||
const reg = this.reg();
|
||||
const stringId = this.strings.intern(k.val.val);
|
||||
this.pushIns({ tag: "mov_string", reg, stringId });
|
||||
|
@ -58,7 +58,7 @@ export type TerKind =
|
||||
|
||||
export type Val =
|
||||
| { tag: "int"; val: number }
|
||||
| { tag: "string"; val: string }
|
||||
| { tag: "str"; val: string }
|
||||
| { tag: "fn"; stmt: ast.Stmt };
|
||||
|
||||
export class FnStringifyer {
|
||||
@ -129,7 +129,7 @@ export class FnStringifyer {
|
||||
|
||||
private val(val: Val): string {
|
||||
switch (val.tag) {
|
||||
case "string":
|
||||
case "str":
|
||||
return JSON.stringify(val.val);
|
||||
case "int":
|
||||
return `${val.val}`;
|
||||
|
@ -45,7 +45,7 @@ export class FnMirGen {
|
||||
this.returnLocal = this.local(fnTy.returnTy);
|
||||
for (const [i, param] of this.stmtKind.params.entries()) {
|
||||
const ty = this.ch.paramTy(this.stmt, i);
|
||||
const local = this.local(ty, param);
|
||||
const local = this.local(ty, param.ident);
|
||||
this.paramLocals.set(i, local);
|
||||
}
|
||||
|
||||
@ -182,6 +182,7 @@ export class FnMirGen {
|
||||
}
|
||||
|
||||
private lowerExpr(expr: ast.Expr) {
|
||||
const ty = this.ch.exprTy(expr);
|
||||
const k = expr.kind;
|
||||
switch (k.tag) {
|
||||
case "error":
|
||||
@ -191,7 +192,6 @@ export class FnMirGen {
|
||||
if (!re) {
|
||||
throw new Error();
|
||||
}
|
||||
const ty = this.ch.exprTy(expr);
|
||||
switch (re.tag) {
|
||||
case "fn": {
|
||||
this.pushStmt({
|
||||
@ -224,7 +224,6 @@ export class FnMirGen {
|
||||
return;
|
||||
}
|
||||
case "int": {
|
||||
const ty = this.ch.exprTy(expr);
|
||||
this.pushStmt({
|
||||
tag: "push",
|
||||
val: { tag: "int", val: k.val },
|
||||
@ -232,11 +231,10 @@ export class FnMirGen {
|
||||
});
|
||||
return;
|
||||
}
|
||||
case "string": {
|
||||
const ty = this.ch.exprTy(expr);
|
||||
case "str": {
|
||||
this.pushStmt({
|
||||
tag: "push",
|
||||
val: { tag: "string", val: k.val },
|
||||
val: { tag: "str", val: k.val },
|
||||
ty,
|
||||
});
|
||||
return;
|
||||
|
@ -1,28 +1,22 @@
|
||||
|
||||
#[c_function("notice")]
|
||||
fn notice() {}
|
||||
fn notice() -> int {}
|
||||
|
||||
#[c_function("print_int")]
|
||||
fn print_int(value) {}
|
||||
fn print_int(value: int) -> int {}
|
||||
|
||||
fn inner(value) {
|
||||
print_int(value);
|
||||
|
||||
|
||||
|
||||
#[c_function("println")]
|
||||
fn println(value: *str) -> int {}
|
||||
|
||||
|
||||
#[c_export("sbc_main")]
|
||||
fn main() -> int {
|
||||
println("hello_world");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let i = 0;
|
||||
loop {
|
||||
if 10 < i + 1 {
|
||||
break;
|
||||
}
|
||||
let a = 4;
|
||||
inner(a + 2);
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// vim: syntax=rust commentstring=//\ %s
|
||||
// vim: syntax=slige commentstring=//\ %s
|
||||
|
||||
|
@ -2,18 +2,24 @@ import * as ast from "./ast.ts";
|
||||
|
||||
export type Ty =
|
||||
| { tag: "error" }
|
||||
| { tag: "unknown" }
|
||||
| { tag: "int" }
|
||||
| { tag: "string" }
|
||||
| { tag: "str" }
|
||||
| { tag: "ptr"; ty: Ty }
|
||||
| { tag: "fn"; stmt: ast.Stmt; params: Ty[]; returnTy: Ty };
|
||||
|
||||
export function tyToString(ty: Ty): string {
|
||||
switch (ty.tag) {
|
||||
case "error":
|
||||
return `<error>`;
|
||||
case "unknown":
|
||||
return `<unknown>`;
|
||||
case "int":
|
||||
return `int`;
|
||||
case "string":
|
||||
return `string`;
|
||||
case "str":
|
||||
return `str`;
|
||||
case "ptr":
|
||||
return `*${tyToString(ty.ty)}`;
|
||||
case "fn": {
|
||||
const k = ty.stmt.kind as ast.StmtKind & { tag: "fn" };
|
||||
const params = ty.params
|
||||
|
Loading…
x
Reference in New Issue
Block a user