fix parsing
This commit is contained in:
@@ -26,14 +26,24 @@ export const run = defineCommand({
|
||||
if (match.succeeded()) {
|
||||
const adapter = semantics(match);
|
||||
const ast = adapter.toAST();
|
||||
// console.log(JSON.stringify(ast, null, 2));
|
||||
new TraitChecker().withModule(ast);
|
||||
const aliasResolvedAst = new TypeAliasResolver().withModule(ast);
|
||||
const typeSystem = new TypeSystem();
|
||||
const typeChecker = new TypeChecker();
|
||||
const typeResolver = new TypeResolver();
|
||||
|
||||
typeChecker.withModule(aliasResolvedAst, typeSystem);
|
||||
typeSystem.solve();
|
||||
try {
|
||||
typeSystem.solve();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log(JSON.stringify(typeSystem.result, null, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
const typeResolvedAst = typeResolver.withModule(aliasResolvedAst, typeSystem);
|
||||
// console.log(JSON.stringify(typeResolvedAst, null, 2));
|
||||
const interpreter = new TreeWalkInterpreter();
|
||||
const result = interpreter.withModule(typeResolvedAst);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
|
||||
@@ -7,13 +7,14 @@ import {
|
||||
LetStatement,
|
||||
Module,
|
||||
Operation,
|
||||
Path,
|
||||
ReturnStatement,
|
||||
StructGetter,
|
||||
StructTypeDeclaration,
|
||||
TypeUsage,
|
||||
} from "../parse/ast";
|
||||
import { contextFromModule } from "./builtins";
|
||||
import { Context, Value } from "./context";
|
||||
import { Context, NamedType, Value } from "./context";
|
||||
|
||||
interface ExpressionResultValue {
|
||||
resultType: "Value";
|
||||
@@ -74,21 +75,21 @@ export class TreeWalkInterpreter {
|
||||
if (result.resultType === "Return") {
|
||||
return result;
|
||||
}
|
||||
if (statement.source.expressionType == "VariableUsage") {
|
||||
if (statement.source.type == "Identifier") {
|
||||
ctx.environment[statement.source.name.text] = {
|
||||
namedEntity: "Variable",
|
||||
value: result.value,
|
||||
};
|
||||
}
|
||||
if (statement.source.expressionType == "StructGetter") {
|
||||
let source = this.withStructGetter(ctx, statement.source);
|
||||
if (statement.source.type == "StructGetter") {
|
||||
let source = this.withStructGetter(ctx, statement.source.source);
|
||||
if (source.resultType === "Return") {
|
||||
return source;
|
||||
}
|
||||
if (source.value.value !== "StructValue") {
|
||||
throw Error("set attr on nonstruct, should never happen due to type system");
|
||||
}
|
||||
source.value.fields[statement.source.attribute.text] = result.value;
|
||||
source.value.fields[statement.source.source.attribute.text] = result.value;
|
||||
}
|
||||
return { resultType: "Value", value: { value: "UnitValue" } };
|
||||
};
|
||||
@@ -163,12 +164,13 @@ export class TreeWalkInterpreter {
|
||||
if (expression.subExpression.expressionType === "FunctionCall") {
|
||||
return this.withFunctionCall(ctx, expression.subExpression);
|
||||
}
|
||||
if (expression.subExpression.expressionType === "VariableUsage") {
|
||||
const variableValue = ctx.environment[expression.subExpression.name.text];
|
||||
if (!variableValue || variableValue.namedEntity !== "Variable") {
|
||||
throw Error(`not found: ${expression.subExpression.name.text}`);
|
||||
}
|
||||
return { resultType: "Value", value: variableValue.value };
|
||||
if (expression.subExpression.expressionType === "Path") {
|
||||
// const variableValue = ctx.environment[expression.subExpression.name.text];
|
||||
// if (!variableValue || variableValue.namedEntity !== "Variable") {
|
||||
// throw Error(`not found: ${expression.subExpression.name.text}`);
|
||||
// }
|
||||
const value = this.withPath(ctx, expression.subExpression);
|
||||
return { resultType: "Value", value: value };
|
||||
}
|
||||
if (expression.subExpression.expressionType === "IfExpression") {
|
||||
const condition = this.withExpression(ctx, expression.subExpression.condition);
|
||||
@@ -302,4 +304,42 @@ export class TreeWalkInterpreter {
|
||||
value: { value: "NumericValue", number: left.value.number / right.value.number },
|
||||
};
|
||||
};
|
||||
|
||||
withPath = (ctx: Context, path: Path): Value => {
|
||||
if (path.value.type == "Identifier") {
|
||||
const variableValue = ctx.environment[path.value.name.text];
|
||||
if (!variableValue || variableValue.namedEntity !== "Variable") {
|
||||
throw Error(`not found: ${path.value.name.text}`);
|
||||
}
|
||||
return variableValue.value;
|
||||
}
|
||||
if (path.value.type == "Nested") {
|
||||
return this.withPathItem(ctx, path) as Value;
|
||||
}
|
||||
throw Error(`Impossible path`);
|
||||
};
|
||||
|
||||
withPathItem = (ctx: Context, path: Path): NamedType | Value => {
|
||||
if (path.value.type == "Identifier") {
|
||||
const envValue = ctx.environment[path.value.name.text];
|
||||
if (!envValue || envValue.namedEntity !== "NamedType") {
|
||||
throw Error(`not found: ${path.value.name.text}`);
|
||||
}
|
||||
return envValue;
|
||||
}
|
||||
if (path.value.type == "Nested") {
|
||||
const envValue = this.withPathItem(ctx, path.value.parent) as NamedType;
|
||||
if (envValue.isA == "Trait") {
|
||||
throw Error(`Cannot get function impl from raw trait`);
|
||||
}
|
||||
for (const impl of envValue.impls) {
|
||||
for (const [name, method] of Object.entries(impl.functions)) {
|
||||
if (name == path.value.name.text) {
|
||||
return { value: "FunctionValue", partial: [], ref: method };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw Error(`Impossible path`);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,6 +57,13 @@ export interface StructGetter {
|
||||
type: TypeUsage;
|
||||
}
|
||||
|
||||
export interface Path {
|
||||
expressionType: "Path";
|
||||
value:
|
||||
| { type: "Identifier"; name: Identifier }
|
||||
| { type: "Nested"; parent: Path; name: Identifier };
|
||||
}
|
||||
|
||||
export interface Operation {
|
||||
expressionType: "Operation";
|
||||
left: Expression;
|
||||
@@ -65,12 +72,6 @@ export interface Operation {
|
||||
type: TypeUsage;
|
||||
}
|
||||
|
||||
export interface VariableUsage {
|
||||
expressionType: "VariableUsage";
|
||||
name: Identifier;
|
||||
type: TypeUsage;
|
||||
}
|
||||
|
||||
export interface IfExpression {
|
||||
expressionType: "IfExpression";
|
||||
condition: Expression;
|
||||
@@ -88,8 +89,8 @@ export interface Expression {
|
||||
| LiteralString
|
||||
| LiteralStruct
|
||||
| FunctionCall
|
||||
| VariableUsage
|
||||
| IfExpression
|
||||
| Path
|
||||
| StructGetter
|
||||
| Block
|
||||
| Operation;
|
||||
@@ -110,7 +111,7 @@ export interface LetStatement {
|
||||
|
||||
export interface AssignmentStatement {
|
||||
statementType: "AssignmentStatement";
|
||||
source: VariableUsage | StructGetter;
|
||||
source: { type: "Identifier"; name: Identifier } | { type: "StructGetter"; source: StructGetter };
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
@@ -139,7 +140,7 @@ export interface Function {
|
||||
block: Block;
|
||||
}
|
||||
|
||||
export const functionToType = (fn: FunctionDeclaration): TypeUsage => {
|
||||
export const functionToType = (fn: FunctionDeclaration): FunctionTypeUsage => {
|
||||
return {
|
||||
typeUsage: "FunctionTypeUsage",
|
||||
arguments: fn.arguments.map((arg) => arg.type),
|
||||
|
||||
@@ -4,8 +4,8 @@ export const boringGrammar = ohm.grammar(String.raw`
|
||||
Boringlang {
|
||||
ReturnStatement = "return" Expression ";"
|
||||
LetStatement = "let" identifier (":" TypeUsage)? "=" Expression ";"
|
||||
AssignmentStatement = VariableUsage "=" Expression ";"
|
||||
| StructGetter "=" Expression ";"
|
||||
AssignmentStatement = identifier "=" Expression ";" -- identifier
|
||||
| StructGetter "=" Expression ";" -- getter
|
||||
ExpressionStatement = Expression ";"
|
||||
Statement = ExpressionStatement
|
||||
| LetStatement
|
||||
@@ -19,27 +19,33 @@ export const boringGrammar = ohm.grammar(String.raw`
|
||||
LiteralStructField = identifier ":" Expression
|
||||
LiteralStruct = identifier "{" ListOf<LiteralStructField, ","> "}"
|
||||
identifier = (letter | "_")+(letter | digit | "_")*
|
||||
FunctionCall = Expression "(" ListOf<Expression, ","> ")"
|
||||
StructGetter = Expression "." identifier
|
||||
VariableUsage = identifier
|
||||
IfExpression = "if" "(" Expression ")" Block ("else" Block)?
|
||||
Term = LiteralInt
|
||||
Path = Path "::" identifier -- nested
|
||||
| identifier -- base
|
||||
PrimaryExpression = LiteralInt
|
||||
| LiteralFloat
|
||||
| LiteralBool
|
||||
| LiteralString
|
||||
| LiteralStruct
|
||||
| IfExpression
|
||||
| Block
|
||||
| Path -- path
|
||||
| "(" Expression ")" -- parens
|
||||
| VariableUsage
|
||||
Factor = Factor "*" Term -- mult
|
||||
| Factor "/" Term -- div
|
||||
| Term
|
||||
Expression = Expression "+" Factor -- plus
|
||||
| Expression "-" Factor -- minus
|
||||
| StructGetter
|
||||
| FunctionCall
|
||||
| Factor
|
||||
StructExpression = LiteralStruct
|
||||
| Block
|
||||
| IfExpression
|
||||
| PrimaryExpression
|
||||
MemberExpression = MemberExpression "." identifier -- structGetter
|
||||
| StructExpression
|
||||
CallExpression = CallExpression "." identifier -- structGetter
|
||||
| CallExpression "(" ListOf<Expression, ","> ")" -- functionCall
|
||||
| MemberExpression "(" ListOf<Expression, ","> ")" -- memberFunctionCall
|
||||
| MemberExpression
|
||||
MultExpression = MultExpression "*" CallExpression -- mult
|
||||
| MultExpression "/" CallExpression -- div
|
||||
| CallExpression
|
||||
AddExpression = Expression "+" MultExpression -- plus
|
||||
| Expression "-" MultExpression -- minus
|
||||
| MultExpression
|
||||
Expression = AddExpression
|
||||
Block = "{" Statement* Expression? "}"
|
||||
NamedTypeUsage = identifier
|
||||
TypeUsage = NamedTypeUsage
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
NamedTypeUsage,
|
||||
newNever,
|
||||
Operation,
|
||||
Path,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StructField,
|
||||
@@ -31,7 +32,6 @@ import {
|
||||
TraitTypeDeclaration,
|
||||
TypeDeclaration,
|
||||
TypeUsage,
|
||||
VariableUsage,
|
||||
} from "./ast";
|
||||
import { boringGrammar } from "./grammar";
|
||||
|
||||
@@ -44,44 +44,60 @@ function nextUnknown() {
|
||||
|
||||
export const semantics = boringGrammar.createSemantics();
|
||||
semantics.addOperation<any>("toAST", {
|
||||
LiteralInt(a): LiteralInt {
|
||||
LiteralInt(a): Expression {
|
||||
return {
|
||||
expressionType: "LiteralInt",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "i64", spanStart: 0, spanEnd: 0 },
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "LiteralInt",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "i64", spanStart: 0, spanEnd: 0 },
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
LiteralFloat(_1, _2, _3): LiteralFloat {
|
||||
LiteralFloat(_1, _2, _3): Expression {
|
||||
return {
|
||||
expressionType: "LiteralFloat",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "f64", spanStart: 0, spanEnd: 0 },
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "LiteralFloat",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "f64", spanStart: 0, spanEnd: 0 },
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
LiteralBool(_): LiteralBool {
|
||||
LiteralBool(_): Expression {
|
||||
return {
|
||||
expressionType: "LiteralBool",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "bool", spanStart: 0, spanEnd: 0 },
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "LiteralBool",
|
||||
value: this.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "bool", spanStart: 0, spanEnd: 0 },
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
LiteralString(_1, text, _3): LiteralString {
|
||||
LiteralString(_1, text, _3): Expression {
|
||||
return {
|
||||
expressionType: "LiteralString",
|
||||
value: text.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "String", spanStart: 0, spanEnd: 0 },
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "LiteralString",
|
||||
value: text.sourceString,
|
||||
type: {
|
||||
typeUsage: "NamedTypeUsage",
|
||||
name: { text: "String", spanStart: 0, spanEnd: 0 },
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
LiteralStructField(identifier, _2, expression): StructField {
|
||||
@@ -90,12 +106,16 @@ semantics.addOperation<any>("toAST", {
|
||||
expression: expression.toAST(),
|
||||
};
|
||||
},
|
||||
LiteralStruct(identifier, _2, fields, _4): LiteralStruct {
|
||||
LiteralStruct(identifier, _2, fields, _4): Expression {
|
||||
return {
|
||||
expressionType: "LiteralStruct",
|
||||
name: identifier.toAST(),
|
||||
fields: fields.asIteration().children.map((c) => c.toAST()),
|
||||
type: { typeUsage: "NamedTypeUsage", name: identifier.toAST() },
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "LiteralStruct",
|
||||
name: identifier.toAST(),
|
||||
fields: fields.asIteration().children.map((c) => c.toAST()),
|
||||
type: { typeUsage: "NamedTypeUsage", name: identifier.toAST() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
identifier(_1, _2): Identifier {
|
||||
@@ -105,95 +125,183 @@ semantics.addOperation<any>("toAST", {
|
||||
spanEnd: this.source.endIdx,
|
||||
};
|
||||
},
|
||||
FunctionCall(expression, _2, args, _4): FunctionCall {
|
||||
const resolvedArgs = args.asIteration().children.map((c) => c.toAST());
|
||||
return {
|
||||
expressionType: "FunctionCall",
|
||||
source: expression.toAST(),
|
||||
arguments: resolvedArgs,
|
||||
type: {
|
||||
typeUsage: "UnknownTypeUsage",
|
||||
name: nextUnknown(),
|
||||
},
|
||||
};
|
||||
PrimaryExpression(literal): Expression {
|
||||
return literal.toAST();
|
||||
},
|
||||
StructGetter(expression, _2, identifier): StructGetter {
|
||||
return {
|
||||
expressionType: "StructGetter",
|
||||
source: expression.toAST(),
|
||||
attribute: identifier.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
VariableUsage(identifier): VariableUsage {
|
||||
return {
|
||||
expressionType: "VariableUsage",
|
||||
name: identifier.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
IfExpression(_1, _2, expression, _4, block, _6, elseBlock): IfExpression {
|
||||
const eb = elseBlock.toAST();
|
||||
return {
|
||||
expressionType: "IfExpression",
|
||||
condition: expression.toAST(),
|
||||
block: block.toAST(),
|
||||
else: eb.length > 0 ? eb[0] : null,
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Term(term): Expression {
|
||||
return term.toAST();
|
||||
},
|
||||
Term_parens(_1, term, _3): Expression {
|
||||
return term.toAST();
|
||||
},
|
||||
Factor(factor): Expression {
|
||||
return factor.toAST();
|
||||
},
|
||||
Expression(expression): Expression {
|
||||
PrimaryExpression_path(path): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: expression.toAST(),
|
||||
subExpression: path.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Expression_plus(expression, _2, factor): Operation {
|
||||
PrimaryExpression_parens(_1, term, _3): Expression {
|
||||
return term.toAST();
|
||||
},
|
||||
StructExpression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
MemberExpression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
MemberExpression_structGetter(expression, _2, identifier): Expression {
|
||||
return {
|
||||
expressionType: "Operation",
|
||||
left: expression.toAST(),
|
||||
op: "+",
|
||||
right: factor.toAST(),
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "StructGetter",
|
||||
source: expression.toAST(),
|
||||
attribute: identifier.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Expression_minus(expression, _2, factor): Operation {
|
||||
CallExpression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
CallExpression_structGetter(expression, _2, identifier): Expression {
|
||||
return {
|
||||
expressionType: "Operation",
|
||||
left: expression.toAST(),
|
||||
op: "-",
|
||||
right: factor.toAST(),
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "StructGetter",
|
||||
source: expression.toAST(),
|
||||
attribute: identifier.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Factor_mult(factor, _2, term): Operation {
|
||||
CallExpression_functionCall(expression, _2, args, _4): Expression {
|
||||
const resolvedArgs = args.asIteration().children.map((c) => c.toAST());
|
||||
return {
|
||||
expressionType: "Operation",
|
||||
left: factor.toAST(),
|
||||
op: "*",
|
||||
right: term.toAST(),
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "FunctionCall",
|
||||
source: expression.toAST(),
|
||||
arguments: resolvedArgs,
|
||||
type: {
|
||||
typeUsage: "UnknownTypeUsage",
|
||||
name: nextUnknown(),
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Factor_div(factor, _2, term): Operation {
|
||||
CallExpression_memberFunctionCall(expression, _2, args, _4): Expression {
|
||||
const resolvedArgs = args.asIteration().children.map((c) => c.toAST());
|
||||
return {
|
||||
expressionType: "Operation",
|
||||
left: factor.toAST(),
|
||||
op: "/",
|
||||
right: term.toAST(),
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "FunctionCall",
|
||||
source: expression.toAST(),
|
||||
arguments: resolvedArgs,
|
||||
type: {
|
||||
typeUsage: "UnknownTypeUsage",
|
||||
name: nextUnknown(),
|
||||
},
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
StructGetter(expression, _2, identifier): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "StructGetter",
|
||||
source: expression.toAST(),
|
||||
attribute: identifier.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
IfExpression(_1, _2, expression, _4, block, _6, elseBlock): Expression {
|
||||
const eb = elseBlock.toAST();
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "IfExpression",
|
||||
condition: expression.toAST(),
|
||||
block: block.toAST(),
|
||||
else: eb.length > 0 ? eb[0] : null,
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Path_base(identifier): Path {
|
||||
return {
|
||||
expressionType: "Path",
|
||||
value: { type: "Identifier", name: identifier.toAST() },
|
||||
};
|
||||
},
|
||||
Path_nested(basePath, _2, attrIdent): Path {
|
||||
return {
|
||||
expressionType: "Path",
|
||||
value: { type: "Nested", parent: basePath.toAST(), name: attrIdent.toAST() },
|
||||
};
|
||||
},
|
||||
MultExpression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
MultExpression_mult(factor, _2, term): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "Operation",
|
||||
left: factor.toAST(),
|
||||
op: "*",
|
||||
right: term.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
MultExpression_div(factor, _2, term): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "Operation",
|
||||
left: factor.toAST(),
|
||||
op: "/",
|
||||
right: term.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
AddExpression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
AddExpression_plus(expression, _2, factor): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "Operation",
|
||||
left: expression.toAST(),
|
||||
op: "+",
|
||||
right: factor.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
AddExpression_minus(expression, _2, factor): Expression {
|
||||
return {
|
||||
statementType: "Expression",
|
||||
subExpression: {
|
||||
expressionType: "Operation",
|
||||
left: expression.toAST(),
|
||||
op: "-",
|
||||
right: factor.toAST(),
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
},
|
||||
type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
Expression(expression): Expression {
|
||||
return expression.toAST();
|
||||
},
|
||||
Statement(statement): Statement {
|
||||
return statement.toAST();
|
||||
},
|
||||
@@ -212,10 +320,17 @@ semantics.addOperation<any>("toAST", {
|
||||
type: tu.length > 0 ? tu[0] : { typeUsage: "UnknownTypeUsage", name: nextUnknown() },
|
||||
};
|
||||
},
|
||||
AssignmentStatement(variable, _2, expression, _4): AssignmentStatement {
|
||||
AssignmentStatement_identifier(variable, _2, expression, _4): AssignmentStatement {
|
||||
return {
|
||||
statementType: "AssignmentStatement",
|
||||
source: variable.toAST(),
|
||||
source: { type: "Identifier", name: variable.toAST() },
|
||||
expression: expression.toAST(),
|
||||
};
|
||||
},
|
||||
AssignmentStatement_getter(variable, _2, expression, _4): AssignmentStatement {
|
||||
return {
|
||||
statementType: "AssignmentStatement",
|
||||
source: { type: "StructGetter", source: variable.toAST() },
|
||||
expression: expression.toAST(),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NamedTypeUsage, TypeUsage } from "../parse/ast";
|
||||
import { FunctionTypeUsage, NamedTypeUsage, TypeUsage } from "../parse/ast";
|
||||
|
||||
interface EnvImpl {
|
||||
trait: string | null;
|
||||
functions: Record<string, TypeUsage>;
|
||||
functions: Record<string, FunctionTypeUsage>;
|
||||
}
|
||||
|
||||
interface NamedType {
|
||||
@@ -35,11 +35,20 @@ export function getAttr(ctx: Context, name: string, field: string) {
|
||||
let results: TypeUsage[] = [];
|
||||
for (const impl of struct.impls) {
|
||||
if (impl.functions[field]) {
|
||||
results.push(impl.functions[field]);
|
||||
const fn = impl.functions[field];
|
||||
|
||||
if (
|
||||
fn.arguments.length &&
|
||||
fn.arguments[0].typeUsage == "NamedTypeUsage" &&
|
||||
fn.arguments[0].name.text === name
|
||||
) {
|
||||
const fnCopy = deepCopy(fn);
|
||||
fnCopy.arguments = fnCopy.arguments.slice(1);
|
||||
results.push(fnCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results.length === 0) {
|
||||
console.log(JSON.stringify(struct, null, 2));
|
||||
throw Error(`${name} has no attribue ${field}`);
|
||||
}
|
||||
if (results.length > 1) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
StructTypeDeclaration,
|
||||
TraitTypeDeclaration,
|
||||
TypeUsage,
|
||||
VariableUsage,
|
||||
Path,
|
||||
} from "../parse/ast";
|
||||
import { deepCopy, replaceType } from "./context";
|
||||
|
||||
@@ -121,11 +121,14 @@ export class TypeAliasResolver {
|
||||
|
||||
withAssignmentStatement = (ctx: AliasContext, statement: AssignmentStatement) => {
|
||||
const result = deepCopy(statement);
|
||||
if (statement.source.expressionType == "StructGetter") {
|
||||
result.source = this.withStructGetter(ctx, statement.source);
|
||||
if (statement.source.type == "StructGetter") {
|
||||
result.source = {
|
||||
type: "StructGetter",
|
||||
source: this.withStructGetter(ctx, statement.source.source),
|
||||
};
|
||||
}
|
||||
if (statement.source.expressionType == "VariableUsage") {
|
||||
result.source = this.withVariableUsage(ctx, statement.source);
|
||||
if (statement.source.type == "Identifier") {
|
||||
result.source = deepCopy(result.source);
|
||||
}
|
||||
result.expression = this.withExpression(ctx, statement.expression);
|
||||
return result;
|
||||
@@ -151,8 +154,8 @@ export class TypeAliasResolver {
|
||||
if (expression.subExpression.expressionType === "FunctionCall") {
|
||||
result.subExpression = this.withFunctionCall(ctx, expression.subExpression);
|
||||
}
|
||||
if (expression.subExpression.expressionType === "VariableUsage") {
|
||||
result.subExpression = this.withVariableUsage(ctx, expression.subExpression);
|
||||
if (expression.subExpression.expressionType === "Path") {
|
||||
result.subExpression = deepCopy(expression.subExpression);
|
||||
}
|
||||
if (expression.subExpression.expressionType === "IfExpression") {
|
||||
result.subExpression = this.withIfExpression(ctx, expression.subExpression);
|
||||
@@ -196,14 +199,6 @@ export class TypeAliasResolver {
|
||||
return result;
|
||||
};
|
||||
|
||||
withVariableUsage = (ctx: AliasContext, variableUsage: VariableUsage) => {
|
||||
const result = deepCopy(variableUsage);
|
||||
for (const [oldName, newType] of Object.entries(ctx.environment)) {
|
||||
result.type = replaceType(oldName, newType, variableUsage.type);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
withIfExpression = (ctx: AliasContext, ifExpression: IfExpression) => {
|
||||
const result = deepCopy(ifExpression);
|
||||
result.condition = this.withExpression(ctx, ifExpression.condition);
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
StructTypeDeclaration,
|
||||
TraitTypeDeclaration,
|
||||
TypeUsage,
|
||||
VariableUsage,
|
||||
Path,
|
||||
Identifier,
|
||||
FunctionTypeUsage,
|
||||
} from "../parse/ast";
|
||||
import { newContext } from "./builtins";
|
||||
import { Context, deepCopy, typeExists } from "./context";
|
||||
@@ -45,17 +47,9 @@ export class TypeChecker {
|
||||
if (ctx.environment[item.name.text]) {
|
||||
throw Error("Duplicate name of trait");
|
||||
}
|
||||
const functions: Record<string, TypeUsage> = {};
|
||||
const functions: Record<string, FunctionTypeUsage> = {};
|
||||
for (const fn of item.functions) {
|
||||
if (
|
||||
fn.arguments.length &&
|
||||
fn.arguments[0].type.typeUsage == "NamedTypeUsage" &&
|
||||
fn.arguments[0].type.name.text === item.name.text
|
||||
) {
|
||||
const fnCopy = deepCopy(fn);
|
||||
fnCopy.arguments = fnCopy.arguments.slice(1);
|
||||
functions[fn.name.text] = functionToType(fnCopy);
|
||||
}
|
||||
functions[fn.name.text] = functionToType(fn);
|
||||
}
|
||||
ctx.environment[item.name.text] = {
|
||||
namedEntity: "NamedType",
|
||||
@@ -86,17 +80,9 @@ export class TypeChecker {
|
||||
if (!struct || struct.namedEntity !== "NamedType" || struct.isA !== "Struct") {
|
||||
throw Error("Impl for non-struct");
|
||||
}
|
||||
const functions: Record<string, TypeUsage> = {};
|
||||
const functions: Record<string, FunctionTypeUsage> = {};
|
||||
for (const fn of item.functions) {
|
||||
if (
|
||||
fn.declaration.arguments.length &&
|
||||
fn.declaration.arguments[0].type.typeUsage == "NamedTypeUsage" &&
|
||||
fn.declaration.arguments[0].type.name.text === item.struct.name.text
|
||||
) {
|
||||
const fnCopy = deepCopy(fn.declaration);
|
||||
fnCopy.arguments = fnCopy.arguments.slice(1);
|
||||
functions[fn.declaration.name.text] = functionToType(fnCopy);
|
||||
}
|
||||
functions[fn.declaration.name.text] = functionToType(fn.declaration);
|
||||
}
|
||||
struct.impls.push({
|
||||
trait: item.trait?.name.text ?? null,
|
||||
@@ -208,18 +194,25 @@ export class TypeChecker {
|
||||
statement: AssignmentStatement,
|
||||
typeSystem: TypeSystem,
|
||||
) => {
|
||||
if (statement.source.expressionType == "StructGetter") {
|
||||
this.withStructGetter(ctx, statement.source, typeSystem);
|
||||
if (statement.source.type == "StructGetter") {
|
||||
this.withStructGetter(ctx, statement.source.source, typeSystem);
|
||||
typeSystem.compare({
|
||||
left: statement.source.source.type,
|
||||
operation: { operation: "equals" },
|
||||
right: statement.expression.type,
|
||||
});
|
||||
}
|
||||
if (statement.source.expressionType == "VariableUsage") {
|
||||
this.withVariableUsage(ctx, statement.source, typeSystem);
|
||||
if (statement.source.type == "Identifier") {
|
||||
typeSystem.compare({
|
||||
left: this.withPath(ctx, {
|
||||
expressionType: "Path",
|
||||
value: { type: "Identifier", name: statement.source.name },
|
||||
}),
|
||||
operation: { operation: "equals" },
|
||||
right: statement.expression.type,
|
||||
});
|
||||
}
|
||||
this.withExpression(ctx, statement.expression, typeSystem);
|
||||
typeSystem.compare({
|
||||
left: statement.source.type,
|
||||
operation: { operation: "equals" },
|
||||
right: statement.expression.type,
|
||||
});
|
||||
};
|
||||
|
||||
withLetStatement = (ctx: Context, statement: LetStatement, typeSystem: TypeSystem) => {
|
||||
@@ -291,12 +284,11 @@ export class TypeChecker {
|
||||
right: expression.subExpression.type,
|
||||
});
|
||||
}
|
||||
if (expression.subExpression.expressionType === "VariableUsage") {
|
||||
this.withVariableUsage(ctx, expression.subExpression, typeSystem);
|
||||
if (expression.subExpression.expressionType === "Path") {
|
||||
typeSystem.compare({
|
||||
left: expression.type,
|
||||
operation: { operation: "equals" },
|
||||
right: expression.subExpression.type,
|
||||
right: this.withPath(ctx, expression.subExpression),
|
||||
});
|
||||
}
|
||||
if (expression.subExpression.expressionType === "IfExpression") {
|
||||
@@ -377,16 +369,41 @@ export class TypeChecker {
|
||||
}
|
||||
};
|
||||
|
||||
withVariableUsage = (ctx: Context, usage: VariableUsage, typeSystem: TypeSystem) => {
|
||||
const variable = ctx.environment[usage.name.text];
|
||||
if (!variable || variable.namedEntity === "NamedType") {
|
||||
throw new Error(`${usage.name.text} not found.`);
|
||||
withPath = (ctx: Context, path: Path): TypeUsage => {
|
||||
const pathList: Identifier[] = [];
|
||||
while (path.value.type == "Nested") {
|
||||
pathList.unshift(path.value.name);
|
||||
path = path.value.parent;
|
||||
}
|
||||
typeSystem.compare({
|
||||
left: variable.type,
|
||||
operation: { operation: "equals" },
|
||||
right: usage.type,
|
||||
});
|
||||
pathList.unshift(path.value.name);
|
||||
|
||||
if (pathList.length === 0 || pathList.length > 2) {
|
||||
throw new Error(`Namespaces not yet supported`);
|
||||
}
|
||||
if (pathList.length === 1) {
|
||||
const variable = ctx.environment[pathList[0].text];
|
||||
if (!variable || variable.namedEntity === "NamedType") {
|
||||
throw new Error(`${pathList[0].text} not found.`);
|
||||
}
|
||||
return variable.type;
|
||||
}
|
||||
|
||||
let struct = ctx.environment[pathList[0].text];
|
||||
if (!struct) {
|
||||
throw new Error(`Unknown ${pathList[0].text}`);
|
||||
}
|
||||
if (struct.namedEntity == "Variable") {
|
||||
throw new Error(`Cannot "::" variable ${pathList[0].text}`);
|
||||
}
|
||||
if (struct.fields[pathList[1].text]) {
|
||||
return struct.fields[pathList[1].text];
|
||||
}
|
||||
for (const impl of struct.impls) {
|
||||
if (impl.functions[pathList[1].text]) {
|
||||
return impl.functions[pathList[1].text];
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not find attr ${pathList[1].text}`);
|
||||
};
|
||||
|
||||
withIfExpression = (ctx: Context, ifExpression: IfExpression, typeSystem: TypeSystem) => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
StructTypeDeclaration,
|
||||
TraitTypeDeclaration,
|
||||
TypeUsage,
|
||||
VariableUsage,
|
||||
Path,
|
||||
} from "../parse/ast";
|
||||
import { newContext } from "./builtins";
|
||||
import { Context, deepCopy, typeExists } from "./context";
|
||||
@@ -109,11 +109,11 @@ export class TypeResolver {
|
||||
|
||||
withAssignmentStatement = (statement: AssignmentStatement, typeSystem: TypeSystem) => {
|
||||
const result = deepCopy(statement);
|
||||
if (statement.source.expressionType == "StructGetter") {
|
||||
result.source = this.withStructGetter(statement.source, typeSystem);
|
||||
}
|
||||
if (statement.source.expressionType == "VariableUsage") {
|
||||
result.source = this.withVariableUsage(statement.source, typeSystem);
|
||||
if (statement.source.type == "StructGetter") {
|
||||
result.source = {
|
||||
type: "StructGetter",
|
||||
source: this.withStructGetter(statement.source.source, typeSystem),
|
||||
};
|
||||
}
|
||||
result.expression = this.withExpression(statement.expression, typeSystem);
|
||||
return result;
|
||||
@@ -142,8 +142,8 @@ export class TypeResolver {
|
||||
if (expression.subExpression.expressionType === "FunctionCall") {
|
||||
result.subExpression = this.withFunctionCall(expression.subExpression, typeSystem);
|
||||
}
|
||||
if (expression.subExpression.expressionType === "VariableUsage") {
|
||||
result.subExpression = this.withVariableUsage(expression.subExpression, typeSystem);
|
||||
if (expression.subExpression.expressionType === "Path") {
|
||||
// paths do not have types
|
||||
}
|
||||
if (expression.subExpression.expressionType === "IfExpression") {
|
||||
result.subExpression = this.withIfExpression(expression.subExpression, typeSystem);
|
||||
@@ -179,12 +179,6 @@ export class TypeResolver {
|
||||
return result;
|
||||
};
|
||||
|
||||
withVariableUsage = (usage: VariableUsage, typeSystem: TypeSystem) => {
|
||||
const result = deepCopy(usage);
|
||||
result.type = typeSystem.resolveType(usage.type);
|
||||
return result;
|
||||
};
|
||||
|
||||
withIfExpression = (ifExpression: IfExpression, typeSystem: TypeSystem) => {
|
||||
const result = deepCopy(ifExpression);
|
||||
result.type = typeSystem.resolveType(ifExpression.type);
|
||||
|
||||
@@ -4,7 +4,9 @@ import { Context, deepCopy, getAttr } from "./context";
|
||||
|
||||
export const compareTypes = (typeA: TypeUsage, typeB: TypeUsage) => {
|
||||
if (typeA.typeUsage !== typeB.typeUsage) {
|
||||
throw Error(`Mismatched types: ${typeA.typeUsage} ${typeB.typeUsage}`);
|
||||
throw Error(
|
||||
`Mismatched types: ${JSON.stringify(typeA, null, 2)} ${JSON.stringify(typeB, null, 2)}`,
|
||||
);
|
||||
}
|
||||
if (typeA.typeUsage == "NamedTypeUsage" && typeB.typeUsage == "NamedTypeUsage") {
|
||||
if (typeB.name.text === "Never") {
|
||||
|
||||
Reference in New Issue
Block a user