mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-15 00:45:04 +01:00
name resolution
This commit is contained in:
parent
cc2a9aeca8
commit
35f1c92e36
6 changed files with 449 additions and 60 deletions
277
src/ast.ts
277
src/ast.ts
|
|
@ -1,5 +1,13 @@
|
|||
import { Span } from "./error";
|
||||
|
||||
export type Ast = Item[];
|
||||
|
||||
export type Identifier = {
|
||||
name: string;
|
||||
span: Span;
|
||||
res?: Resolution;
|
||||
};
|
||||
|
||||
export type ItemKind = {
|
||||
kind: "function";
|
||||
node: FunctionDef;
|
||||
|
|
@ -22,40 +30,67 @@ export type FunctionArg = {
|
|||
span: Span;
|
||||
};
|
||||
|
||||
export type ExprEmpty = { kind: "empty" };
|
||||
|
||||
export type ExprLet = {
|
||||
kind: "let";
|
||||
name: string;
|
||||
type?: Type;
|
||||
rhs: Expr;
|
||||
after: Expr;
|
||||
};
|
||||
|
||||
export type ExprBlock = {
|
||||
kind: "block";
|
||||
exprs: Expr[];
|
||||
};
|
||||
|
||||
export type ExprLiteral = {
|
||||
kind: "literal";
|
||||
value: Literal;
|
||||
};
|
||||
|
||||
export type ExprIdent = {
|
||||
kind: "ident";
|
||||
value: Identifier;
|
||||
};
|
||||
|
||||
export type ExprBinary = {
|
||||
kind: "binary";
|
||||
binaryKind: BinaryKind;
|
||||
lhs: Expr;
|
||||
rhs: Expr;
|
||||
};
|
||||
|
||||
export type ExprUnary = {
|
||||
kind: "unary";
|
||||
unaryKind: UnaryKind;
|
||||
rhs: Expr;
|
||||
};
|
||||
|
||||
export type ExprCall = {
|
||||
kind: "call";
|
||||
lhs: Expr;
|
||||
args: Expr[];
|
||||
};
|
||||
|
||||
export type ExprIf = {
|
||||
kind: "if";
|
||||
cond: Expr;
|
||||
then: Expr;
|
||||
else?: Expr;
|
||||
};
|
||||
|
||||
export type ExprKind =
|
||||
| { kind: "empty" }
|
||||
| { kind: "let"; name: string; type?: Type; rhs: Expr; after: Expr }
|
||||
| { kind: "block"; exprs: Expr[] }
|
||||
| {
|
||||
kind: "literal";
|
||||
value: Literal;
|
||||
}
|
||||
| {
|
||||
kind: "ident";
|
||||
value: string;
|
||||
}
|
||||
| {
|
||||
kind: "binary";
|
||||
binaryKind: BinaryKind;
|
||||
lhs: Expr;
|
||||
rhs: Expr;
|
||||
}
|
||||
| {
|
||||
kind: "unary";
|
||||
unaryKind: UnaryKind;
|
||||
rhs: Expr;
|
||||
}
|
||||
| {
|
||||
kind: "call";
|
||||
lhs: Expr;
|
||||
args: Expr[];
|
||||
}
|
||||
| {
|
||||
kind: "if";
|
||||
cond: Expr;
|
||||
then: Expr;
|
||||
else?: Expr;
|
||||
};
|
||||
| ExprEmpty
|
||||
| ExprLet
|
||||
| ExprBlock
|
||||
| ExprLiteral
|
||||
| ExprIdent
|
||||
| ExprBinary
|
||||
| ExprUnary
|
||||
| ExprCall
|
||||
| ExprIf;
|
||||
|
||||
export type Expr = ExprKind & {
|
||||
span: Span;
|
||||
|
|
@ -126,7 +161,7 @@ export const UNARY_KINDS: UnaryKind[] = ["!", "-"];
|
|||
export type TypeKind =
|
||||
| {
|
||||
kind: "ident";
|
||||
value: string;
|
||||
value: Identifier;
|
||||
}
|
||||
| {
|
||||
kind: "list";
|
||||
|
|
@ -140,3 +175,177 @@ export type TypeKind =
|
|||
export type Type = TypeKind & {
|
||||
span: Span;
|
||||
};
|
||||
|
||||
export type Resolution =
|
||||
| {
|
||||
kind: "local";
|
||||
/**
|
||||
* The index of the local variable, from inside out.
|
||||
* ```
|
||||
* let a in let b in (a, b);
|
||||
* ^ ^
|
||||
* 1 0
|
||||
* ```
|
||||
* When traversing resolutions, a stack of locals has to be kept.
|
||||
* It's similar to a De Bruijn index.
|
||||
*/
|
||||
index: number;
|
||||
}
|
||||
| {
|
||||
kind: "item";
|
||||
/**
|
||||
* Items are numbered in the order they appear in.
|
||||
* Right now we only have one scope of items (global)
|
||||
* so this is enough.
|
||||
*/
|
||||
index: number;
|
||||
}
|
||||
| {
|
||||
kind: "builtin";
|
||||
};
|
||||
|
||||
// folders
|
||||
|
||||
export type FoldFn<T> = (value: T) => T;
|
||||
|
||||
export type Folder = {
|
||||
item: FoldFn<Item>;
|
||||
expr: FoldFn<Expr>;
|
||||
ident: FoldFn<Identifier>;
|
||||
type: FoldFn<Type>;
|
||||
};
|
||||
|
||||
export const DEFAULT_FOLDER: Folder = {
|
||||
item(item) {
|
||||
return super_fold_item(item, this);
|
||||
},
|
||||
expr(expr) {
|
||||
return super_fold_expr(expr, this);
|
||||
},
|
||||
ident(ident) {
|
||||
return ident;
|
||||
},
|
||||
type(type) {
|
||||
return super_fold_type(type, this);
|
||||
},
|
||||
};
|
||||
|
||||
export function fold_ast(ast: Ast, folder: Folder): Ast {
|
||||
return ast.map((item) => folder.item(item));
|
||||
}
|
||||
|
||||
export function super_fold_item(item: Item, folder: Folder): Item {
|
||||
switch (item.kind) {
|
||||
case "function": {
|
||||
const args = item.node.args.map(({ name, type, span }) => ({
|
||||
name,
|
||||
type: folder.type(type),
|
||||
span,
|
||||
}));
|
||||
|
||||
return {
|
||||
kind: "function",
|
||||
span: item.span,
|
||||
node: {
|
||||
name: item.node.name,
|
||||
args,
|
||||
body: folder.expr(item.node.body),
|
||||
returnType: item.node.returnType && folder.type(item.node.returnType),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function super_fold_expr(expr: Expr, folder: Folder): Expr {
|
||||
const span = expr.span;
|
||||
switch (expr.kind) {
|
||||
case "empty": {
|
||||
return { kind: "empty", span };
|
||||
}
|
||||
case "let": {
|
||||
return {
|
||||
kind: "let",
|
||||
name: expr.name,
|
||||
type: expr.type && folder.type(expr.type),
|
||||
rhs: folder.expr(expr.rhs),
|
||||
after: folder.expr(expr.after),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "block": {
|
||||
return {
|
||||
kind: "block",
|
||||
exprs: expr.exprs.map((expr) => folder.expr(expr)),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "literal": {
|
||||
return { kind: "literal", value: expr.value, span };
|
||||
}
|
||||
case "ident": {
|
||||
return { kind: "ident", value: folder.ident(expr.value), span };
|
||||
}
|
||||
case "binary": {
|
||||
return {
|
||||
kind: "binary",
|
||||
binaryKind: expr.binaryKind,
|
||||
lhs: folder.expr(expr.lhs),
|
||||
rhs: folder.expr(expr.rhs),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "unary": {
|
||||
return {
|
||||
kind: "unary",
|
||||
unaryKind: expr.unaryKind,
|
||||
rhs: folder.expr(expr.rhs),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "call": {
|
||||
return {
|
||||
kind: "call",
|
||||
lhs: folder.expr(expr.lhs),
|
||||
args: expr.args.map((expr) => folder.expr(expr)),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "if": {
|
||||
return {
|
||||
kind: "if",
|
||||
cond: folder.expr(expr.cond),
|
||||
then: folder.expr(expr.then),
|
||||
else: expr.else && folder.expr(expr.else),
|
||||
span,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function super_fold_type(type: Type, folder: Folder): Type {
|
||||
const span = type.span;
|
||||
switch (type.kind) {
|
||||
case "ident": {
|
||||
return {
|
||||
kind: "ident",
|
||||
value: folder.ident(type.value),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "list": {
|
||||
return {
|
||||
kind: "list",
|
||||
elem: folder.type(type.elem),
|
||||
span,
|
||||
};
|
||||
}
|
||||
case "tuple": {
|
||||
return {
|
||||
kind: "tuple",
|
||||
elems: type.elems.map((type) => folder.type(type)),
|
||||
span,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue