add type analysis for consts
- add the basics of recursive type resolving for expressions - set err context for enum
This commit is contained in:
parent
1040eef79f
commit
cb8908dc80
6 changed files with 142 additions and 12 deletions
|
@ -1,5 +1,9 @@
|
||||||
// import std;
|
// import std;
|
||||||
|
|
||||||
|
const (
|
||||||
|
AWOO = 1 + 2
|
||||||
|
)
|
||||||
|
|
||||||
enum B {
|
enum B {
|
||||||
a
|
a
|
||||||
b
|
b
|
||||||
|
|
|
@ -73,10 +73,11 @@ pub const BinaryExpr = struct {
|
||||||
|
|
||||||
pub const UnaryOperator = enum {
|
pub const UnaryOperator = enum {
|
||||||
Not,
|
Not,
|
||||||
|
Negate,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const UnaryExpr = struct {
|
pub const UnaryExpr = struct {
|
||||||
op: Token,
|
op: UnaryOperator,
|
||||||
right: *Expr,
|
right: *Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -191,8 +191,28 @@ fn printBinOp(inner: var) void {
|
||||||
std.debug.warn(")");
|
std.debug.warn(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printSingleOp(tok: []const u8, applied: *const Expr) void {
|
const unary_operator_tokens = [_][]const u8{
|
||||||
std.debug.warn("({}", tok);
|
"!", "-",
|
||||||
|
};
|
||||||
|
|
||||||
|
const unary_operators = [_]UnaryOperator{
|
||||||
|
.Not, .Negate,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn unOpToStr(op: UnaryOperator) ?[]const u8 {
|
||||||
|
inline for (unary_operators) |val, idx| {
|
||||||
|
if (val == op) return unary_operator_tokens[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printSingleOp(op: UnaryOperator, applied: *const Expr) void {
|
||||||
|
printSimpleOp(unOpToStr(op), applied);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printSimpleOp(op: ?[]const u8, applied: *const Expr) void {
|
||||||
|
std.debug.warn("({}", op);
|
||||||
printExpr(applied);
|
printExpr(applied);
|
||||||
std.debug.warn(")");
|
std.debug.warn(")");
|
||||||
}
|
}
|
||||||
|
@ -201,8 +221,8 @@ pub fn printExpr(expr: *const Expr) void {
|
||||||
switch (expr.*) {
|
switch (expr.*) {
|
||||||
.Binary => |binary| printBinOp(binary),
|
.Binary => |binary| printBinOp(binary),
|
||||||
|
|
||||||
.Unary => |unary| printSingleOp(unary.op.lexeme, unary.right),
|
.Unary => |unary| printSingleOp(unary.op, unary.right),
|
||||||
.Grouping => |expr_ptr| printSingleOp("group", expr_ptr),
|
.Grouping => |expr_ptr| printSimpleOp("group", expr_ptr),
|
||||||
|
|
||||||
.Literal => |literal| {
|
.Literal => |literal| {
|
||||||
switch (literal) {
|
switch (literal) {
|
||||||
|
@ -282,7 +302,7 @@ pub fn printExpr(expr: *const Expr) void {
|
||||||
|
|
||||||
pub fn printStmt(ident: usize, stmt: *const Stmt) void {
|
pub fn printStmt(ident: usize, stmt: *const Stmt) void {
|
||||||
switch (stmt.*) {
|
switch (stmt.*) {
|
||||||
.Println => |expr| printSingleOp("println", expr),
|
.Println => |expr| printSimpleOp("println", expr),
|
||||||
.Expr => |expr| printExpr(expr),
|
.Expr => |expr| printExpr(expr),
|
||||||
|
|
||||||
.If => |ifstmt| {
|
.If => |ifstmt| {
|
||||||
|
@ -405,6 +425,10 @@ pub fn printContext(ctx: CompilationContext) void {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.Const => |typ| {
|
||||||
|
std.debug.warn("const '{}', typ={}\n", kv.key, prettyType(typ));
|
||||||
|
},
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("TODO handle print of {}\n", kv.value);
|
std.debug.warn("TODO handle print of {}\n", kv.value);
|
||||||
unreachable;
|
unreachable;
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub const SymbolType = enum {
|
||||||
Struct,
|
Struct,
|
||||||
Enum,
|
Enum,
|
||||||
Variable,
|
Variable,
|
||||||
|
Const,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SymbolData = union(SymbolType) {
|
pub const SymbolData = union(SymbolType) {
|
||||||
|
@ -78,6 +79,7 @@ pub const SymbolData = union(SymbolType) {
|
||||||
// variables (parameters and variables), for the type system
|
// variables (parameters and variables), for the type system
|
||||||
// only have types
|
// only have types
|
||||||
Variable: SymbolUnderlyingType,
|
Variable: SymbolUnderlyingType,
|
||||||
|
Const: SymbolUnderlyingType,
|
||||||
};
|
};
|
||||||
|
|
||||||
const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
|
const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
|
||||||
|
@ -175,4 +177,8 @@ pub const CompilationContext = struct {
|
||||||
.Enum = ident_map,
|
.Enum = ident_map,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insertConst(self: *@This(), constdecl: ast.SingleConst, typ: SymbolUnderlyingType) !void {
|
||||||
|
_ = try self.symbol_table.put(constdecl.name.lexeme, SymbolData{ .Const = typ });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,6 +61,24 @@ fn toBinaryOperator(op: Token) !ast.BinaryOperator {
|
||||||
return ParseError.UnknownOperator;
|
return ParseError.UnknownOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unary_operator_tokens = [_][]const u8{
|
||||||
|
"!", "-",
|
||||||
|
};
|
||||||
|
|
||||||
|
const unary_operators = [_]ast.UnaryOperator{
|
||||||
|
.Not, .Negate,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn toUnaryOperator(op: Token) !ast.UnaryOperator {
|
||||||
|
const lex = op.lexeme;
|
||||||
|
|
||||||
|
inline for (unary_operator_tokens) |op_str, idx| {
|
||||||
|
if (std.mem.eql(u8, lex, op_str)) return unary_operators[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseError.UnknownOperator;
|
||||||
|
}
|
||||||
|
|
||||||
pub const Parser = struct {
|
pub const Parser = struct {
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
scanner: *Scanner,
|
scanner: *Scanner,
|
||||||
|
@ -241,9 +259,7 @@ pub const Parser = struct {
|
||||||
return grouping;
|
return grouping;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr {
|
fn mkUnary(self: *Parser, op: ast.UnaryOperator, right: *Expr) !*Expr {
|
||||||
std.debug.warn("Unary\n");
|
|
||||||
|
|
||||||
var expr = try self.allocator.create(Expr);
|
var expr = try self.allocator.create(Expr);
|
||||||
expr.* = Expr{
|
expr.* = Expr{
|
||||||
.Unary = ast.UnaryExpr{
|
.Unary = ast.UnaryExpr{
|
||||||
|
@ -1015,7 +1031,7 @@ pub const Parser = struct {
|
||||||
var op = self.previous();
|
var op = self.previous();
|
||||||
var right = try self.parseUnary();
|
var right = try self.parseUnary();
|
||||||
|
|
||||||
return try self.mkUnary(op, right);
|
return try self.mkUnary(try toUnaryOperator(op), right);
|
||||||
}
|
}
|
||||||
|
|
||||||
var expr = try self.parseCall();
|
var expr = try self.parseCall();
|
||||||
|
|
|
@ -88,11 +88,80 @@ pub const TypeSolver = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolveExprType(
|
||||||
|
self: *@This(),
|
||||||
|
ctx: *comp.CompilationContext,
|
||||||
|
expr: *const ast.Expr,
|
||||||
|
) anyerror!SymbolUnderlyingType {
|
||||||
|
switch (expr.*) {
|
||||||
|
.Binary => |binary| {
|
||||||
|
var left_type = self.resolveExprType(ctx, binary.left);
|
||||||
|
var right_type = self.resolveExprType(ctx, binary.right);
|
||||||
|
|
||||||
|
return switch (binary.op) {
|
||||||
|
// all numeric operations return numeric types
|
||||||
|
.Add, .Sub, .Mul, .Div, .Mod => left_type,
|
||||||
|
|
||||||
|
// TODO check left and right as numeric
|
||||||
|
.Greater, .GreaterEqual, .Less, .LessEqual => SymbolUnderlyingType{ .Bool = {} },
|
||||||
|
|
||||||
|
// all boolean ops return bools
|
||||||
|
.Equal, .And, .Or => SymbolUnderlyingType{ .Bool = {} },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// for now, unary operators only have .Not
|
||||||
|
.Unary => |unary| {
|
||||||
|
var right_type = self.resolveExprType(ctx, unary.right);
|
||||||
|
return switch (unary.op) {
|
||||||
|
.Negate => right_type,
|
||||||
|
.Not => right_type,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.Literal => |literal| {
|
||||||
|
return switch (literal) {
|
||||||
|
.Bool => SymbolUnderlyingType{ .Bool = {} },
|
||||||
|
|
||||||
|
// TODO determine its i64 depending of parseInt results
|
||||||
|
.Integer => SymbolUnderlyingType{ .Integer32 = {} },
|
||||||
|
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.Grouping => |group_expr| return try self.resolveExprType(ctx, group_expr),
|
||||||
|
|
||||||
|
.Struct => |struc| blk: {
|
||||||
|
const name = struc.name.lexeme;
|
||||||
|
var typ = self.resolveGlobalType(ctx, name);
|
||||||
|
if (typ == null) {
|
||||||
|
self.doError("Unknown struct name '{}'\n", name);
|
||||||
|
return CompileError.TypeError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return typ.?;
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO variable resolution
|
||||||
|
|
||||||
|
// TODO Get (for structs and enums)
|
||||||
|
|
||||||
|
else => {
|
||||||
|
std.debug.warn("TODO resolve expr {}\n", ast.ExprType(expr.*));
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn nodePass(
|
pub fn nodePass(
|
||||||
self: *@This(),
|
self: *@This(),
|
||||||
ctx: *comp.CompilationContext,
|
ctx: *comp.CompilationContext,
|
||||||
node: *ast.Node,
|
node: *ast.Node,
|
||||||
) !void {
|
) !void {
|
||||||
|
self.setErrToken(null);
|
||||||
|
self.setErrContext(null);
|
||||||
|
|
||||||
switch (node.*) {
|
switch (node.*) {
|
||||||
.Root => unreachable,
|
.Root => unreachable,
|
||||||
.FnDecl => |decl| {
|
.FnDecl => |decl| {
|
||||||
|
@ -145,11 +214,21 @@ pub const TypeSolver = struct {
|
||||||
|
|
||||||
// TODO change enums to u32
|
// TODO change enums to u32
|
||||||
.Enum => |enu| {
|
.Enum => |enu| {
|
||||||
|
self.setErrToken(enu.name);
|
||||||
|
self.setErrContext("enum {}", enu.name.lexeme);
|
||||||
|
|
||||||
try ctx.insertEnum(enu);
|
try ctx.insertEnum(enu);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO infer type of expr in const
|
.ConstDecl => |constlist| {
|
||||||
//.ConstDecl => {},
|
for (constlist.toSlice()) |constdecl| {
|
||||||
|
self.setErrToken(constdecl.name);
|
||||||
|
self.setErrContext("const {}", constdecl.name.lexeme);
|
||||||
|
|
||||||
|
var expr_type = try self.resolveExprType(ctx, constdecl.expr);
|
||||||
|
try ctx.insertConst(constdecl, expr_type);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("TODO type analysis of {}\n", node.*);
|
std.debug.warn("TODO type analysis of {}\n", node.*);
|
||||||
|
|
Loading…
Reference in a new issue