add "variable metadata"

this is inserted in the analysis pass into a map from expr ptrs to
metadata in the compilation context itself, this enables codegen to
fetch that metadata with the expr pointer

the other approach was embedding it into the variable expr itself (as
seen by VariableExpr), but that causes a compiler crash
This commit is contained in:
Luna 2019-09-27 17:08:01 -03:00
parent 362fc7e3ef
commit 7def9abc5a
4 changed files with 58 additions and 11 deletions

View File

@ -186,6 +186,8 @@ pub const TypeSolver = struct {
// TODO make return type optional and so, skip exprs that
// fail to be fully resolved, instead of returning CompileError
// TODO make the expr ptr a const since we want to implicit cast things
pub fn resolveExprType(
self: *@This(),
ctx: *comp.CompilationContext,
@ -276,9 +278,10 @@ pub const TypeSolver = struct {
},
.Variable => |vari| {
// TODO maybe we can modify vari and add the current scope
// it was found for codegen purposes
return try ctx.resolveVarType(vari.lexeme);
self.setErrToken(vari);
var metadata = try ctx.resolveVarType(vari.lexeme);
try ctx.insertMetadata(expr, metadata);
return metadata.typ;
},
.Get => |get| {

View File

@ -141,6 +141,11 @@ pub const SetExpr = struct {
value: *Expr,
};
pub const VariableExpr = struct {
tok: Token,
metadata: ?*comp.VariableMetadata = null,
};
pub const Expr = union(ExprType) {
Assign: AssignExpr,
@ -150,6 +155,7 @@ pub const Expr = union(ExprType) {
Struct: StructExpr,
Variable: Token,
Grouping: *Expr,
Call: CallExpr,

View File

@ -128,6 +128,31 @@ const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool };
const Using = enum {
Scope,
Function,
};
pub const VariableMetadata = struct {
typ: SymbolUnderlyingType,
using: Using,
from_scope: ?*Scope = null,
from_function: ?*FunctionSymbol = null,
pub fn withScope(scope: *Scope, typ: SymbolUnderlyingType) VariableMetadata {
return VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope };
}
pub fn withParam(func: *FunctionSymbol, typ: SymbolUnderlyingType) VariableMetadata {
return VariableMetadata{ .typ = typ, .from_function = func, .using = .Function };
}
};
// TODO rm const?
pub const VariableMetadataMap = std.AutoHashMap(*const ast.Expr, VariableMetadata);
/// Represents the context for a full compiler run.
/// This is used to manage the symbol table for the compilation unit, etc.
pub const CompilationContext = struct {
@ -137,13 +162,21 @@ pub const CompilationContext = struct {
cur_function: ?*FunctionSymbol = null,
current_scope: ?*Scope = null,
metadata_map: VariableMetadataMap,
pub fn init(allocator: *std.mem.Allocator) CompilationContext {
return CompilationContext{
.allocator = allocator,
.symbol_table = SymbolTable.init(allocator),
.metadata_map = VariableMetadataMap.init(allocator),
};
}
pub fn deinit(self: *@This()) void {
self.symbol_table.deinit();
self.metadata_map.deinit();
}
/// Create a new scope out of the current one and set it as the current.
pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
if (self.current_scope == null) {
@ -297,21 +330,21 @@ pub const CompilationContext = struct {
self: *@This(),
scope_opt: ?*Scope,
name: []const u8,
) ?SymbolUnderlyingType {
) ?VariableMetadata {
if (scope_opt == null) return null;
var scope = scope_opt.?;
var kv_opt = scope.env.get(name);
if (kv_opt) |kv| {
// TODO maybe return the scope it was found in
return kv.value;
return VariableMetadata.withScope(scope, kv.value);
} else {
return self.resolveVarTypeInScope(scope.parent, name);
}
}
fn resolveVarType(self: *@This(), name: []const u8) !SymbolUnderlyingType {
var var_type: ?SymbolUnderlyingType = null;
/// Resolve a given name's type, assuming it is a variable.
pub fn resolveVarType(self: *@This(), name: []const u8) !VariableMetadata {
var var_type: ?VariableMetadata = null;
if (self.current_scope) |scope| {
var_type = self.resolveVarTypeInScope(scope, name);
@ -320,10 +353,15 @@ pub const CompilationContext = struct {
if (self.cur_function) |cur_function| {
var kv_opt = cur_function.parameters.get(name);
if (kv_opt) |kv| return kv.value;
if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value);
}
std.debug.warn("Unknown name {}\n", name);
return CompilationError.UnknownName;
}
pub fn insertMetadata(self: *@This(), ptr: *const ast.Expr, metadata: VariableMetadata) !void {
std.debug.assert(ast.ExprType(ptr.*) == .Variable);
_ = try self.metadata_map.put(ptr, metadata);
}
};

View File

@ -412,9 +412,9 @@ pub const Parser = struct {
return expr;
}
fn mkVariable(self: *Parser, variable: Token) !*ast.Expr {
fn mkVariable(self: *Parser, tok: Token) !*ast.Expr {
var expr = try self.allocator.create(Expr);
expr.* = Expr{ .Variable = variable };
expr.* = Expr{ .Variable = tok };
return expr;
}