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

View File

@@ -41,6 +41,7 @@ export interface LiteralStruct {
name: Identifier;
fields: StructField[];
type: TypeUsage;
typeParameters: GenericUsage;
}
export interface FunctionCall {
@@ -55,10 +56,12 @@ export interface StructGetter {
source: Expression;
attribute: Identifier;
type: TypeUsage;
typeParameters: GenericUsage;
}
export interface Path {
expressionType: "Path";
typeParameters: GenericUsage;
value:
| { type: "Identifier"; name: Identifier }
| { type: "Nested"; parent: Path; name: Identifier };
@@ -130,6 +133,7 @@ export interface FunctionArgument {
export interface FunctionDeclaration {
name: Identifier;
generic: GenericDeclaration;
arguments: FunctionArgument[];
returnType: TypeUsage;
}
@@ -157,6 +161,7 @@ export interface StructTypeDeclaration {
moduleItem: "StructTypeDeclaration";
typeDeclaration: "StructTypeDeclaration";
name: Identifier;
generic: GenericDeclaration;
fields: StructTypeField[];
}
@@ -164,6 +169,7 @@ export interface TraitTypeDeclaration {
moduleItem: "TraitTypeDeclaration";
typeDeclaration: "TraitTypeDeclaration";
name: Identifier;
generic: GenericDeclaration;
functions: FunctionDeclaration[];
}
@@ -171,6 +177,7 @@ export type TypeDeclaration = StructTypeDeclaration | TraitTypeDeclaration;
export interface Impl {
moduleItem: "Impl";
generic: GenericDeclaration;
struct: NamedTypeUsage;
trait: NamedTypeUsage | null;
functions: Function[];
@@ -182,8 +189,29 @@ export interface Module {
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 {
typeUsage: "NamedTypeUsage";
typeParameters: GenericUsage;
name: Identifier;
}
@@ -203,6 +231,7 @@ export type TypeUsage = NamedTypeUsage | FunctionTypeUsage | UnknownTypeUsage;
export const newVoid: () => TypeUsage = () => {
return {
typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
name: { text: "Void", spanStart: 0, spanEnd: 0 },
};
};
@@ -210,6 +239,7 @@ export const newVoid: () => TypeUsage = () => {
export const newNever: () => TypeUsage = () => {
return {
typeUsage: "NamedTypeUsage",
typeParameters: { genericUsage: "Known", parameters: [] },
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`
Boringlang {
GenericUsage = "[" ListOf<TypeUsage, ","> "]"
GenericParameter = identifier ":" ListOf<TypeUsage, "+"> -- conditions
| identifier
GenericDeclaration = "[" ListOf<GenericParameter, ","> "]"
ReturnStatement = "return" Expression ";"
LetStatement = "let" identifier (":" TypeUsage)? "=" Expression ";"
AssignmentStatement = identifier "=" Expression ";" -- identifier
@@ -17,12 +21,12 @@ export const boringGrammar = ohm.grammar(String.raw`
LiteralString = "\"" (~"\"" any)* "\""
| "'" (~"'" any)* "'"
LiteralStructField = identifier ":" Expression
LiteralStruct = identifier "{" ListOf<LiteralStructField, ","> "}"
LiteralStruct = identifier (GenericUsage)? "{" ListOf<LiteralStructField, ","> "}"
identifier = (letter | "_")+(letter | digit | "_")*
StructGetter = Expression "." identifier
IfExpression = "if" "(" Expression ")" Block ("else" Block)?
Path = Path "::" identifier -- nested
| identifier -- base
Path = Path "::" identifier (GenericUsage)? -- nested
| identifier (GenericUsage)? -- base
PrimaryExpression = LiteralInt
| LiteralFloat
| LiteralBool
@@ -33,9 +37,9 @@ export const boringGrammar = ohm.grammar(String.raw`
| Block
| IfExpression
| PrimaryExpression
MemberExpression = MemberExpression "." identifier -- structGetter
MemberExpression = MemberExpression "." identifier (GenericUsage)? -- structGetter
| StructExpression
CallExpression = CallExpression "." identifier -- structGetter
CallExpression = CallExpression "." identifier (GenericUsage)? -- structGetter
| CallExpression "(" ListOf<Expression, ","> ")" -- functionCall
| MemberExpression "(" ListOf<Expression, ","> ")" -- memberFunctionCall
| MemberExpression
@@ -47,19 +51,19 @@ export const boringGrammar = ohm.grammar(String.raw`
| MultExpression
Expression = AddExpression
Block = "{" Statement* Expression? "}"
NamedTypeUsage = identifier
NamedTypeUsage = identifier (GenericUsage)?
TypeUsage = NamedTypeUsage
| "fn" "(" ListOf<TypeUsage, ","> ")" ":" TypeUsage -- function_tu
FunctionArgument = identifier ":" TypeUsage
FunctionDeclaration = "fn" identifier "(" ListOf<FunctionArgument, ","> ")" ":" TypeUsage
FunctionDeclaration = "fn" identifier (GenericDeclaration)? "(" ListOf<FunctionArgument, ","> ")" ":" TypeUsage
Function = FunctionDeclaration Block
StructTypeField = identifier ":" TypeUsage
StructTypeDeclaration = "type" identifier "struct" "{" ListOf<StructTypeField, ","> "}"
StructTypeDeclaration = "type" identifier (GenericDeclaration)? "struct" "{" ListOf<StructTypeField, ","> "}"
TraitMethod = FunctionDeclaration ";"
TraitTypeDeclaration = "type" identifier "trait" "{" TraitMethod* "}"
TraitTypeDeclaration = "type" identifier (GenericDeclaration)? "trait" "{" TraitMethod* "}"
TypeDeclaration = StructTypeDeclaration
| TraitTypeDeclaration
Impl = "impl" (NamedTypeUsage "for")? NamedTypeUsage "{" Function* "}"
Impl = "impl" (GenericDeclaration)? (NamedTypeUsage "for")? NamedTypeUsage "{" Function* "}"
ModuleItem = Function
| TypeDeclaration
| Impl

View File

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

View File

@@ -24,7 +24,7 @@ export interface Context {
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];
if (!struct || struct.namedEntity !== "NamedType") {
throw Error(`Unknown type ${name}`);