Compare commits

...

2 Commits

Author SHA1 Message Date
8f6200f393 added generics ast 2026-01-20 17:47:36 -07:00
e7eb194b6c added type info to getaddr 2025-10-10 20:49:11 -06:00
5 changed files with 143 additions and 26 deletions

View File

@@ -2,11 +2,11 @@ type MyTrait trait {}
type Pair[K, V: MyTrait] struct { type Pair[K, V: MyTrait] struct {
k: K, k: K,
v: V, v: V
} }
type Value struct { type Value struct {
value: i64, value: i64
} }
impl MyTrait for Value {} impl MyTrait for Value {}
@@ -21,7 +21,7 @@ impl [K, V: MyTrait] Pair[K, V] {
fn main(): i64 { fn main(): i64 {
let a = Pair[i64, Value]{ let a = Pair[i64, Value]{
k: 4, k: 4,
v: Value{value: 6}, v: Value{value: 6}
}; };
return a.get_value[i64](999).value; return a.get_value[i64](999).value;
} }

View File

@@ -41,6 +41,7 @@ export interface LiteralStruct {
name: Identifier; name: Identifier;
fields: StructField[]; fields: StructField[];
type: TypeUsage; type: TypeUsage;
typeParameters: GenericUsage;
} }
export interface FunctionCall { export interface FunctionCall {
@@ -55,10 +56,12 @@ export interface StructGetter {
source: Expression; source: Expression;
attribute: Identifier; attribute: Identifier;
type: TypeUsage; type: TypeUsage;
typeParameters: GenericUsage;
} }
export interface Path { export interface Path {
expressionType: "Path"; expressionType: "Path";
typeParameters: GenericUsage;
value: value:
| { type: "Identifier"; name: Identifier } | { type: "Identifier"; name: Identifier }
| { type: "Nested"; parent: Path; name: Identifier }; | { type: "Nested"; parent: Path; name: Identifier };
@@ -130,6 +133,7 @@ export interface FunctionArgument {
export interface FunctionDeclaration { export interface FunctionDeclaration {
name: Identifier; name: Identifier;
generic: GenericDeclaration;
arguments: FunctionArgument[]; arguments: FunctionArgument[];
returnType: TypeUsage; returnType: TypeUsage;
} }
@@ -157,6 +161,7 @@ export interface StructTypeDeclaration {
moduleItem: "StructTypeDeclaration"; moduleItem: "StructTypeDeclaration";
typeDeclaration: "StructTypeDeclaration"; typeDeclaration: "StructTypeDeclaration";
name: Identifier; name: Identifier;
generic: GenericDeclaration;
fields: StructTypeField[]; fields: StructTypeField[];
} }
@@ -164,6 +169,7 @@ export interface TraitTypeDeclaration {
moduleItem: "TraitTypeDeclaration"; moduleItem: "TraitTypeDeclaration";
typeDeclaration: "TraitTypeDeclaration"; typeDeclaration: "TraitTypeDeclaration";
name: Identifier; name: Identifier;
generic: GenericDeclaration;
functions: FunctionDeclaration[]; functions: FunctionDeclaration[];
} }
@@ -171,6 +177,7 @@ export type TypeDeclaration = StructTypeDeclaration | TraitTypeDeclaration;
export interface Impl { export interface Impl {
moduleItem: "Impl"; moduleItem: "Impl";
generic: GenericDeclaration;
struct: NamedTypeUsage; struct: NamedTypeUsage;
trait: NamedTypeUsage | null; trait: NamedTypeUsage | null;
functions: Function[]; functions: Function[];
@@ -182,8 +189,29 @@ export interface Module {
items: ModuleItem[]; items: ModuleItem[];
} }
export interface GenericParameter {
name: Identifier;
bounds: Identifier[];
}
export interface GenericDeclaration {
parameters: GenericParameter[];
}
export interface KnownGenericUsage {
genericUsage: "Known";
parameters: TypeUsage[];
}
export interface UnknownGenericUsage {
genericUsage: "Unknown";
}
export type GenericUsage = UnknownGenericUsage | KnownGenericUsage;
export interface NamedTypeUsage { export interface NamedTypeUsage {
typeUsage: "NamedTypeUsage"; typeUsage: "NamedTypeUsage";
typeParameters: GenericUsage;
name: Identifier; name: Identifier;
} }
@@ -203,6 +231,7 @@ export type TypeUsage = NamedTypeUsage | FunctionTypeUsage | UnknownTypeUsage;
export const newVoid: () => TypeUsage = () => { export const newVoid: () => TypeUsage = () => {
return { return {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "Void", spanStart: 0, spanEnd: 0 }, name: { text: "Void", spanStart: 0, spanEnd: 0 },
}; };
}; };
@@ -210,6 +239,7 @@ export const newVoid: () => TypeUsage = () => {
export const newNever: () => TypeUsage = () => { export const newNever: () => TypeUsage = () => {
return { return {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "Never", spanStart: 0, spanEnd: 0 }, name: { text: "Never", spanStart: 0, spanEnd: 0 },
}; };
}; };

View File

@@ -2,6 +2,10 @@ import * as ohm from "ohm-js";
export const boringGrammar = ohm.grammar(String.raw` export const boringGrammar = ohm.grammar(String.raw`
Boringlang { Boringlang {
GenericUsage = "[" ListOf<TypeUsage, ","> "]"
GenericParameter = identifier ":" ListOf<TypeUsage, "+"> -- conditions
| identifier
GenericDeclaration = "[" ListOf<GenericParameter, ","> "]"
ReturnStatement = "return" Expression ";" ReturnStatement = "return" Expression ";"
LetStatement = "let" identifier (":" TypeUsage)? "=" Expression ";" LetStatement = "let" identifier (":" TypeUsage)? "=" Expression ";"
AssignmentStatement = identifier "=" Expression ";" -- identifier AssignmentStatement = identifier "=" Expression ";" -- identifier
@@ -17,12 +21,12 @@ export const boringGrammar = ohm.grammar(String.raw`
LiteralString = "\"" (~"\"" any)* "\"" LiteralString = "\"" (~"\"" any)* "\""
| "'" (~"'" any)* "'" | "'" (~"'" any)* "'"
LiteralStructField = identifier ":" Expression LiteralStructField = identifier ":" Expression
LiteralStruct = identifier "{" ListOf<LiteralStructField, ","> "}" LiteralStruct = identifier (GenericUsage)? "{" ListOf<LiteralStructField, ","> "}"
identifier = (letter | "_")+(letter | digit | "_")* identifier = (letter | "_")+(letter | digit | "_")*
StructGetter = Expression "." identifier StructGetter = Expression "." identifier
IfExpression = "if" "(" Expression ")" Block ("else" Block)? IfExpression = "if" "(" Expression ")" Block ("else" Block)?
Path = Path "::" identifier -- nested Path = Path "::" identifier (GenericUsage)? -- nested
| identifier -- base | identifier (GenericUsage)? -- base
PrimaryExpression = LiteralInt PrimaryExpression = LiteralInt
| LiteralFloat | LiteralFloat
| LiteralBool | LiteralBool
@@ -33,9 +37,9 @@ export const boringGrammar = ohm.grammar(String.raw`
| Block | Block
| IfExpression | IfExpression
| PrimaryExpression | PrimaryExpression
MemberExpression = MemberExpression "." identifier -- structGetter MemberExpression = MemberExpression "." identifier (GenericUsage)? -- structGetter
| StructExpression | StructExpression
CallExpression = CallExpression "." identifier -- structGetter CallExpression = CallExpression "." identifier (GenericUsage)? -- structGetter
| CallExpression "(" ListOf<Expression, ","> ")" -- functionCall | CallExpression "(" ListOf<Expression, ","> ")" -- functionCall
| MemberExpression "(" ListOf<Expression, ","> ")" -- memberFunctionCall | MemberExpression "(" ListOf<Expression, ","> ")" -- memberFunctionCall
| MemberExpression | MemberExpression
@@ -47,19 +51,19 @@ export const boringGrammar = ohm.grammar(String.raw`
| MultExpression | MultExpression
Expression = AddExpression Expression = AddExpression
Block = "{" Statement* Expression? "}" Block = "{" Statement* Expression? "}"
NamedTypeUsage = identifier NamedTypeUsage = identifier (GenericUsage)?
TypeUsage = NamedTypeUsage TypeUsage = NamedTypeUsage
| "fn" "(" ListOf<TypeUsage, ","> ")" ":" TypeUsage -- function_tu | "fn" "(" ListOf<TypeUsage, ","> ")" ":" TypeUsage -- function_tu
FunctionArgument = identifier ":" TypeUsage FunctionArgument = identifier ":" TypeUsage
FunctionDeclaration = "fn" identifier "(" ListOf<FunctionArgument, ","> ")" ":" TypeUsage FunctionDeclaration = "fn" identifier (GenericDeclaration)? "(" ListOf<FunctionArgument, ","> ")" ":" TypeUsage
Function = FunctionDeclaration Block Function = FunctionDeclaration Block
StructTypeField = identifier ":" TypeUsage StructTypeField = identifier ":" TypeUsage
StructTypeDeclaration = "type" identifier "struct" "{" ListOf<StructTypeField, ","> "}" StructTypeDeclaration = "type" identifier (GenericDeclaration)? "struct" "{" ListOf<StructTypeField, ","> "}"
TraitMethod = FunctionDeclaration ";" TraitMethod = FunctionDeclaration ";"
TraitTypeDeclaration = "type" identifier "trait" "{" TraitMethod* "}" TraitTypeDeclaration = "type" identifier (GenericDeclaration)? "trait" "{" TraitMethod* "}"
TypeDeclaration = StructTypeDeclaration TypeDeclaration = StructTypeDeclaration
| TraitTypeDeclaration | TraitTypeDeclaration
Impl = "impl" (NamedTypeUsage "for")? NamedTypeUsage "{" Function* "}" Impl = "impl" (GenericDeclaration)? (NamedTypeUsage "for")? NamedTypeUsage "{" Function* "}"
ModuleItem = Function ModuleItem = Function
| TypeDeclaration | TypeDeclaration
| Impl | Impl

View File

@@ -8,6 +8,9 @@ import {
FunctionCall, FunctionCall,
FunctionDeclaration, FunctionDeclaration,
FunctionTypeUsage, FunctionTypeUsage,
GenericDeclaration,
GenericParameter,
GenericUsage,
Identifier, Identifier,
IfExpression, IfExpression,
Impl, Impl,
@@ -44,6 +47,29 @@ function nextUnknown() {
export const semantics = boringGrammar.createSemantics(); export const semantics = boringGrammar.createSemantics();
semantics.addOperation<any>("toAST", { semantics.addOperation<any>("toAST", {
GenericUsage(_1, typeUsage, _3): GenericUsage {
return {
genericUsage: "Known",
parameters: typeUsage.asIteration().children.map((c) => c.toAST()),
};
},
GenericParameter_conditions(identifier, _2, typeUsage): GenericParameter {
return {
name: identifier.toAST(),
bounds: typeUsage.asIteration().children.map((c) => c.toAST()),
};
},
GenericParameter(identifier): GenericParameter {
return {
name: identifier.toAST(),
bounds: [],
};
},
GenericDeclaration(_1, parameters, _2): GenericDeclaration {
return {
parameters: parameters.asIteration().children.map((c) => c.toAST()),
};
},
LiteralInt(a): Expression { LiteralInt(a): Expression {
return { return {
statementType: "Expression", statementType: "Expression",
@@ -52,6 +78,7 @@ semantics.addOperation<any>("toAST", {
value: this.sourceString, value: this.sourceString,
type: { type: {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "i64", spanStart: 0, spanEnd: 0 }, name: { text: "i64", spanStart: 0, spanEnd: 0 },
}, },
}, },
@@ -66,6 +93,7 @@ semantics.addOperation<any>("toAST", {
value: this.sourceString, value: this.sourceString,
type: { type: {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "f64", spanStart: 0, spanEnd: 0 }, name: { text: "f64", spanStart: 0, spanEnd: 0 },
}, },
}, },
@@ -80,6 +108,7 @@ semantics.addOperation<any>("toAST", {
value: this.sourceString, value: this.sourceString,
type: { type: {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "bool", spanStart: 0, spanEnd: 0 }, name: { text: "bool", spanStart: 0, spanEnd: 0 },
}, },
}, },
@@ -94,6 +123,7 @@ semantics.addOperation<any>("toAST", {
value: text.sourceString, value: text.sourceString,
type: { type: {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "String", spanStart: 0, spanEnd: 0 }, name: { text: "String", spanStart: 0, spanEnd: 0 },
}, },
}, },
@@ -106,16 +136,25 @@ semantics.addOperation<any>("toAST", {
expression: expression.toAST(), expression: expression.toAST(),
}; };
}, },
LiteralStruct(identifier, _2, fields, _4): Expression { LiteralStruct(identifier, genericUsage, _2, fields, _4): Expression {
const gu = genericUsage.toAST();
return { return {
statementType: "Expression", statementType: "Expression",
subExpression: { subExpression: {
expressionType: "LiteralStruct", expressionType: "LiteralStruct",
name: identifier.toAST(), name: identifier.toAST(),
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
fields: fields.asIteration().children.map((c) => c.toAST()), fields: fields.asIteration().children.map((c) => c.toAST()),
type: { typeUsage: "NamedTypeUsage", name: identifier.toAST() }, type: {
typeUsage: "NamedTypeUsage",
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
name: identifier.toAST(),
},
},
type: {
typeUsage: "UnknownTypeUsage",
name: nextUnknown(),
}, },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
}; };
}, },
identifier(_1, _2): Identifier { identifier(_1, _2): Identifier {
@@ -144,13 +183,15 @@ semantics.addOperation<any>("toAST", {
MemberExpression(expression): Expression { MemberExpression(expression): Expression {
return expression.toAST(); return expression.toAST();
}, },
MemberExpression_structGetter(expression, _2, identifier): Expression { MemberExpression_structGetter(expression, _2, identifier, genericUsage): Expression {
const gu = genericUsage.toAST();
return { return {
statementType: "Expression", statementType: "Expression",
subExpression: { subExpression: {
expressionType: "StructGetter", expressionType: "StructGetter",
source: expression.toAST(), source: expression.toAST(),
attribute: identifier.toAST(), attribute: identifier.toAST(),
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
}, },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
@@ -159,13 +200,15 @@ semantics.addOperation<any>("toAST", {
CallExpression(expression): Expression { CallExpression(expression): Expression {
return expression.toAST(); return expression.toAST();
}, },
CallExpression_structGetter(expression, _2, identifier): Expression { CallExpression_structGetter(expression, _2, identifier, genericUsage): Expression {
const gu = genericUsage.toAST();
return { return {
statementType: "Expression", statementType: "Expression",
subExpression: { subExpression: {
expressionType: "StructGetter", expressionType: "StructGetter",
source: expression.toAST(), source: expression.toAST(),
attribute: identifier.toAST(), attribute: identifier.toAST(),
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
}, },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
@@ -210,6 +253,7 @@ semantics.addOperation<any>("toAST", {
expressionType: "StructGetter", expressionType: "StructGetter",
source: expression.toAST(), source: expression.toAST(),
attribute: identifier.toAST(), attribute: identifier.toAST(),
typeParameters: { genericUsage: "Unknown" },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
}, },
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
@@ -229,15 +273,19 @@ semantics.addOperation<any>("toAST", {
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
}; };
}, },
Path_base(identifier): Path { Path_base(identifier, genericUsage): Path {
const gu = genericUsage.toAST();
return { return {
expressionType: "Path", expressionType: "Path",
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
value: { type: "Identifier", name: identifier.toAST() }, value: { type: "Identifier", name: identifier.toAST() },
}; };
}, },
Path_nested(basePath, _2, attrIdent): Path { Path_nested(basePath, _2, attrIdent, genericUsage): Path {
const gu = genericUsage.toAST();
return { return {
expressionType: "Path", expressionType: "Path",
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
value: { type: "Nested", parent: basePath.toAST(), name: attrIdent.toAST() }, value: { type: "Nested", parent: basePath.toAST(), name: attrIdent.toAST() },
}; };
}, },
@@ -357,9 +405,11 @@ semantics.addOperation<any>("toAST", {
} }
return block; return block;
}, },
NamedTypeUsage(name): NamedTypeUsage { NamedTypeUsage(name, genericUsage): NamedTypeUsage {
const gu = genericUsage.toAST();
return { return {
typeUsage: "NamedTypeUsage", typeUsage: "NamedTypeUsage",
typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" },
name: name.toAST(), name: name.toAST(),
}; };
}, },
@@ -379,9 +429,20 @@ semantics.addOperation<any>("toAST", {
type: typeUsage.toAST(), type: typeUsage.toAST(),
}; };
}, },
FunctionDeclaration(_1, identifier, _3, args, _4, _5, returnType): FunctionDeclaration { FunctionDeclaration(
_1,
identifier,
genericDeclaration,
_4,
args,
_5,
_6,
returnType,
): FunctionDeclaration {
const gd = genericDeclaration.toAST();
return { return {
name: identifier.toAST(), name: identifier.toAST(),
generic: gd.length ? gd[0] : { parameters: [] },
arguments: args.asIteration().children.map((c) => c.toAST()), arguments: args.asIteration().children.map((c) => c.toAST()),
returnType: returnType.toAST(), returnType: returnType.toAST(),
}; };
@@ -399,32 +460,54 @@ semantics.addOperation<any>("toAST", {
type: typeUsage.toAST(), type: typeUsage.toAST(),
}; };
}, },
StructTypeDeclaration(_1, identifier, _3, _4, fields, _6): StructTypeDeclaration { StructTypeDeclaration(
_1,
identifier,
genericDeclaration,
_4,
_5,
fields,
_7,
): StructTypeDeclaration {
const gd = genericDeclaration.toAST();
return { return {
moduleItem: "StructTypeDeclaration", moduleItem: "StructTypeDeclaration",
typeDeclaration: "StructTypeDeclaration", typeDeclaration: "StructTypeDeclaration",
name: identifier.toAST(), name: identifier.toAST(),
generic: gd.length ? gd[0] : { parameters: [] },
fields: fields.asIteration().children.map((c) => c.toAST()), fields: fields.asIteration().children.map((c) => c.toAST()),
}; };
}, },
TraitMethod(declaration, _2): FunctionDeclaration { TraitMethod(declaration, _2): FunctionDeclaration {
return declaration.toAST(); return declaration.toAST();
}, },
TraitTypeDeclaration(_1, identifier, _3, _4, methods, _5): TraitTypeDeclaration { TraitTypeDeclaration(
_1,
identifier,
genericDeclaration,
_4,
_5,
methods,
_7,
): TraitTypeDeclaration {
const gd = genericDeclaration.toAST();
return { return {
moduleItem: "TraitTypeDeclaration", moduleItem: "TraitTypeDeclaration",
typeDeclaration: "TraitTypeDeclaration", typeDeclaration: "TraitTypeDeclaration",
name: identifier.toAST(), name: identifier.toAST(),
generic: gd.length ? gd[0] : { parameters: [] },
functions: methods.asIteration().children.map((c) => c.toAST()), functions: methods.asIteration().children.map((c) => c.toAST()),
}; };
}, },
TypeDeclaration(declaration): TypeDeclaration { TypeDeclaration(declaration): TypeDeclaration {
return declaration.toAST(); return declaration.toAST();
}, },
Impl(_1, trait, _3, struct, _4, methods, _5): Impl { Impl(_1, genericDeclaration, trait, _4, struct, _6, methods, _8): Impl {
const tr = trait.toAST(); const tr = trait.toAST();
const gd = genericDeclaration.toAST();
return { return {
moduleItem: "Impl", moduleItem: "Impl",
generic: gd.length ? gd[0] : { parameters: [] },
struct: struct.toAST(), struct: struct.toAST(),
trait: tr.length > 0 ? tr[0] : null, trait: tr.length > 0 ? tr[0] : null,
functions: methods.asIteration().children.map((c) => c.toAST()), functions: methods.asIteration().children.map((c) => c.toAST()),

View File

@@ -24,7 +24,7 @@ export interface Context {
environment: Record<string, NamedEntity>; environment: Record<string, NamedEntity>;
} }
export function getAttr(ctx: Context, name: string, field: string) { export function getAttr(ctx: Context, name: string, field: string): TypeUsage {
const struct = ctx.environment[name]; const struct = ctx.environment[name];
if (!struct || struct.namedEntity !== "NamedType") { if (!struct || struct.namedEntity !== "NamedType") {
throw Error(`Unknown type ${name}`); throw Error(`Unknown type ${name}`);