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

View file

@ -141,6 +141,11 @@ pub const SetExpr = struct {
value: *Expr, value: *Expr,
}; };
pub const VariableExpr = struct {
tok: Token,
metadata: ?*comp.VariableMetadata = null,
};
pub const Expr = union(ExprType) { pub const Expr = union(ExprType) {
Assign: AssignExpr, Assign: AssignExpr,
@ -150,6 +155,7 @@ pub const Expr = union(ExprType) {
Struct: StructExpr, Struct: StructExpr,
Variable: Token, Variable: Token,
Grouping: *Expr, Grouping: *Expr,
Call: CallExpr, 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 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. /// Represents the context for a full compiler run.
/// This is used to manage the symbol table for the compilation unit, etc. /// This is used to manage the symbol table for the compilation unit, etc.
pub const CompilationContext = struct { pub const CompilationContext = struct {
@ -137,13 +162,21 @@ pub const CompilationContext = struct {
cur_function: ?*FunctionSymbol = null, cur_function: ?*FunctionSymbol = null,
current_scope: ?*Scope = null, current_scope: ?*Scope = null,
metadata_map: VariableMetadataMap,
pub fn init(allocator: *std.mem.Allocator) CompilationContext { pub fn init(allocator: *std.mem.Allocator) CompilationContext {
return CompilationContext{ return CompilationContext{
.allocator = allocator, .allocator = allocator,
.symbol_table = SymbolTable.init(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. /// 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 { pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
if (self.current_scope == null) { if (self.current_scope == null) {
@ -297,21 +330,21 @@ pub const CompilationContext = struct {
self: *@This(), self: *@This(),
scope_opt: ?*Scope, scope_opt: ?*Scope,
name: []const u8, name: []const u8,
) ?SymbolUnderlyingType { ) ?VariableMetadata {
if (scope_opt == null) return null; if (scope_opt == null) return null;
var scope = scope_opt.?; var scope = scope_opt.?;
var kv_opt = scope.env.get(name); var kv_opt = scope.env.get(name);
if (kv_opt) |kv| { if (kv_opt) |kv| {
// TODO maybe return the scope it was found in return VariableMetadata.withScope(scope, kv.value);
return kv.value;
} else { } else {
return self.resolveVarTypeInScope(scope.parent, name); return self.resolveVarTypeInScope(scope.parent, name);
} }
} }
fn resolveVarType(self: *@This(), name: []const u8) !SymbolUnderlyingType { /// Resolve a given name's type, assuming it is a variable.
var var_type: ?SymbolUnderlyingType = null; pub fn resolveVarType(self: *@This(), name: []const u8) !VariableMetadata {
var var_type: ?VariableMetadata = null;
if (self.current_scope) |scope| { if (self.current_scope) |scope| {
var_type = self.resolveVarTypeInScope(scope, name); var_type = self.resolveVarTypeInScope(scope, name);
@ -320,10 +353,15 @@ pub const CompilationContext = struct {
if (self.cur_function) |cur_function| { if (self.cur_function) |cur_function| {
var kv_opt = cur_function.parameters.get(name); 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); std.debug.warn("Unknown name {}\n", name);
return CompilationError.UnknownName; 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; 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); var expr = try self.allocator.create(Expr);
expr.* = Expr{ .Variable = variable }; expr.* = Expr{ .Variable = tok };
return expr; return expr;
} }